diff --git a/.artifacts b/.artifacts index 92f7a1615ce..27974610f1f 100644 --- a/.artifacts +++ b/.artifacts @@ -35,11 +35,8 @@ dubbo-configcenter-apollo dubbo-configcenter-nacos dubbo-configcenter-zookeeper dubbo-core-spi -dubbo-dependencies dubbo-dependencies-all dubbo-dependencies-bom -dubbo-dependencies-zookeeper-curator5 -dubbo-distribution dubbo-filter-cache dubbo-filter-validation dubbo-kubernetes @@ -75,6 +72,7 @@ dubbo-remoting dubbo-remoting-api dubbo-remoting-http12 dubbo-remoting-http3 +dubbo-remoting-websocket dubbo-remoting-netty dubbo-remoting-netty4 dubbo-remoting-zookeeper-curator5 @@ -90,13 +88,13 @@ dubbo-serialization-fastjson2 dubbo-serialization-hessian2 dubbo-spring-boot dubbo-spring-boot-actuator +dubbo-spring-boot-actuator-autoconfigure dubbo-spring-boot-actuator-compatible dubbo-spring-boot-autoconfigure dubbo-spring-boot-3-autoconfigure dubbo-spring-boot-autoconfigure-compatible +dubbo-spring-boot-actuator-autoconfigure-compatible dubbo-spring-boot-compatible -dubbo-observability-spring-boot-starters -dubbo-observability-spring-boot-autoconfigure dubbo-tracing-brave-zipkin-spring-boot-starter dubbo-tracing-otel-zipkin-spring-boot-starter dubbo-tracing-otel-otlp-spring-boot-starter @@ -105,7 +103,6 @@ dubbo-spring-boot-starter dubbo-spring-boot-starters dubbo-spring-boot-interceptor dubbo-nacos-spring-boot-starter -dubbo-zookeeper-spring-boot-starter dubbo-zookeeper-curator5-spring-boot-starter dubbo-sentinel-spring-boot-starter dubbo-seata-spring-boot-starter @@ -115,4 +112,6 @@ dubbo-xds dubbo-plugin-loom dubbo-rest-jaxrs dubbo-rest-spring +dubbo-rest-openapi dubbo-triple-servlet +dubbo-triple-websocket diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index acc7d007d84..afcac9f890e 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -5,4 +5,4 @@ - [x] Make sure there is a [GitHub_issue](https://github.com/apache/dubbo/issues) field for the change. - [x] Write a pull request description that is detailed enough to understand what the pull request does, how, and why. - [x] Write necessary unit-test to verify your logic correction. If the new feature or significant change is committed, please remember to add sample in [dubbo samples](https://github.com/apache/dubbo-samples) project. -- [x] Make sure gitHub actions can pass. [Why the workflow is failing and how to fix it?](./CONTRIBUTING.md) +- [x] Make sure gitHub actions can pass. [Why the workflow is failing and how to fix it?](../CONTRIBUTING.md) diff --git a/.github/workflows/build-and-test-pr.yml b/.github/workflows/build-and-test-pr.yml index 4b9e933bb45..fd2560825ab 100644 --- a/.github/workflows/build-and-test-pr.yml +++ b/.github/workflows/build-and-test-pr.yml @@ -78,13 +78,13 @@ jobs: needs: check-format runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: "Check License" uses: apache/skywalking-eyes@e1a02359b239bd28de3f6d35fdc870250fa513d5 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: "Set up JDK 21" - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 21 @@ -107,11 +107,9 @@ jobs: version: ${{ steps.dubbo-version.outputs.version }} steps: - name: "Checkout code" - uses: actions/checkout@v3 - with: - path: dubbo + uses: actions/checkout@v4 - name: "Set up JDK" - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 21 @@ -135,7 +133,6 @@ jobs: run: rm -rf ~/.m2/repository/org/apache/dubbo - name: "Build Dubbo with maven" run: | - cd ./dubbo ./mvnw ${{ env.MAVEN_ARGS }} clean install -Psources,'!demo',skip-spotless,checkstyle -Dmaven.test.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper - name: "Save dubbo cache" uses: actions/cache/save@v4 @@ -155,7 +152,7 @@ jobs: shopt -s globstar zip ${{ github.workspace }}/class.zip **/target/classes/* -r - name: "Upload class result" - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: "class-file" path: ${{ github.workspace }}/class.zip @@ -163,7 +160,7 @@ jobs: if: failure() run: zip ${{ github.workspace }}/checkstyle.zip *checkstyle* -r - name: "Upload checkstyle file if failure" - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: "checkstyle-file" @@ -171,7 +168,7 @@ jobs: - name: "Calculate Dubbo Version" id: dubbo-version run: | - REVISION=`awk '/[^<]+<\/revision>/{gsub(/|<\/revision>/,"",$1);print $1;exit;}' ./dubbo/pom.xml` + REVISION=`awk '/[^<]+<\/revision>/{gsub(/|<\/revision>/,"",$1);print $1;exit;}' ./pom.xml` echo "version=$REVISION" >> $GITHUB_OUTPUT echo "dubbo version: $REVISION" @@ -182,7 +179,7 @@ jobs: strategy: fail-fast: false env: - ZOOKEEPER_VERSION: 3.6.3 + ZOOKEEPER_VERSION: 3.7.2 steps: - name: "Cache zookeeper binary archive" uses: actions/cache@v3 @@ -210,7 +207,7 @@ jobs: ls -al ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz unit-test: - needs: [check-format, build-source, unit-test-prepare] + needs: [check-format, unit-test-prepare] name: "Unit Test On ubuntu-latest" runs-on: ubuntu-latest strategy: @@ -218,14 +215,14 @@ jobs: env: DISABLE_FILE_SYSTEM_TEST: true CURRENT_ROLE: ${{ matrix.case-role }} - ZOOKEEPER_VERSION: 3.6.3 + ZOOKEEPER_VERSION: 3.7.2 steps: - name: "Checkout code" - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: "Set up JDK ${{ matrix.jdk }}" - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 21 @@ -251,15 +248,23 @@ jobs: timeout-minutes: 90 run: | set -o pipefail - ./mvnw ${{ env.MAVEN_ARGS }} clean test verify -Pjacoco,jdk15ge-simple,'!jdk15ge','!demo',skip-spotless,jacoco089 -DtrimStackTrace=false -Dmaven.test.skip=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper 2>&1 | tee >(grep -n -B 1 -A 200 "FAILURE! -- in" > test_errors.log) + ./mvnw ${{ env.MAVEN_ARGS }} clean test verify -Pjacoco,jdk15ge-simple,'!jdk15ge','!demo',skip-spotless -DtrimStackTrace=false -Dmaven.test.skip=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper 2>&1 | tee >(grep -n -B 1 -A 200 "FAILURE! -- in" > test_errors.log) - name: "Print test error log" if: failure() run: cat test_errors.log - - name: "Upload coverage result" - uses: actions/upload-artifact@v3 + - name: "Upload coverage to Codecov" + uses: codecov/codecov-action@v5 + with: + token: ${{ secrets.CODECOV_TOKEN }} + verbose: true + flags: unit-tests + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + - name: "Upload surefire reports" + uses: actions/upload-artifact@v4 with: - name: coverage-result - path: "**/target/site/**/jacoco.xml" + name: surefire-reports + path: "**/target/surefire-reports/**" samples-test-prepare: needs: check-format @@ -267,14 +272,14 @@ jobs: env: JOB_COUNT: 3 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-samples' ref: master - name: "Prepare test list" run: bash ./test/scripts/prepare-test.sh - name: "Upload test list" - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: samples-test-list path: test/jobs @@ -289,9 +294,9 @@ jobs: strategy: fail-fast: false matrix: - job_id: [1, 2, 3] + job_id: [1,2,3] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-samples' ref: master @@ -314,12 +319,12 @@ jobs: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }} ${{ runner.os }}-dubbo-snapshot- - name: "Download test list" - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: samples-test-list path: test/jobs/ - name: "Set up JDK 8" - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 8 @@ -335,9 +340,9 @@ jobs: - name: "merge jacoco result" run: cd test/dubbo-test-jacoco-merger && mvn clean compile exec:java -Dexec.mainClass="org.apache.dubbo.test.JacocoMerge" -Dexec.args="${{github.workspace}}" - name: "Upload jacoco" - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: samples-jacoco-result + name: samples-jacoco-result-${{matrix.job_id}} path: target/jacoco*.exec - name: "Upload test result" if: always() @@ -352,7 +357,7 @@ jobs: env: JAVA_VER: 8 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-samples' ref: master @@ -370,14 +375,14 @@ jobs: env: JOB_COUNT: 3 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-integration-cases' ref: main - name: "Prepare test list" run: bash ./test/scripts/prepare-test.sh - name: "Upload test list" - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: test-list path: test/jobs @@ -392,9 +397,9 @@ jobs: strategy: fail-fast: false matrix: - job_id: [1, 2, 3] + job_id: [1,2,3] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-integration-cases' ref: main @@ -417,12 +422,12 @@ jobs: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }} ${{ runner.os }}-dubbo-snapshot- - name: "Download test list" - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: test-list path: test/jobs/ - name: "Set up JDK 8" - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 8 @@ -438,9 +443,9 @@ jobs: - name: "merge jacoco result" run: cd test/dubbo-test-jacoco-merger && mvn clean compile exec:java -Dexec.mainClass="org.apache.dubbo.test.JacocoMerge" -Dexec.args="${{github.workspace}}" - name: "Upload jacoco" - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: jacoco-result + name: jacoco-result-${{matrix.job_id}} path: target/jacoco*.exec - name: "Upload test result" if: always() @@ -455,7 +460,7 @@ jobs: env: JAVA_VER: 8 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-integration-cases' ref: main @@ -467,77 +472,111 @@ jobs: - name: "Merge test result" run: ./test/scripts/merge-test-results.sh - jacoco-result-merge: + samples-jacoco-result-merge: runs-on: ubuntu-latest - needs: [check-format, integration-test-result, samples-test-result, unit-test] + needs: [check-format, samples-test-result] steps: - - uses: actions/checkout@v3 - with: - path: "./dubbo" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-samples' path: "./dubbo-samples" - - uses: actions/checkout@v3 + - name: "Set up JDK 21" + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: 21 + - name: "Restore class result" + uses: actions/download-artifact@v4 + with: + name: "class-file" + github-token: ${{ secrets.GITHUB_TOKEN }} + path: ${{ github.workspace }} + - name: "Unpack class result" + run: | + unzip -o ${{ github.workspace }}/class.zip + - name: "Restore samples jacoco exec" + uses: actions/download-artifact@v4 + with: + pattern: samples-jacoco-result-* + github-token: ${{ secrets.GITHUB_TOKEN }} + path: dubbo-samples/target/ + - name: "Merge samples jacoco result" + run: | + cd ${{ github.workspace }}/dubbo-samples/test/dubbo-test-jacoco-merger + mvn clean compile exec:java -Dexec.mainClass="org.apache.dubbo.test.JacocoReport" -Dexec.args="${{github.workspace}}/dubbo-samples ${{github.workspace}}" + - name: "Remove old test result" + run: | + rm -rf ${{ github.workspace }}/dubbo-samples + - name: "Upload coverage to Codecov" + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + flags: samples-tests + verbose: true + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + + integration-jacoco-result-merge: + runs-on: ubuntu-latest + needs: [check-format, integration-test-result, samples-test-result] + steps: + - uses: actions/checkout@v4 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-integration-cases' path: "./dubbo-integration-cases" - name: "Set up JDK 21" - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 21 - name: "Restore class result" - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: "class-file" + github-token: ${{ secrets.GITHUB_TOKEN }} path: ${{ github.workspace }} - name: "Unpack class result" run: | - cd ${{ github.workspace }}/dubbo unzip -o ${{ github.workspace }}/class.zip - - name: "Restore jacoco exec" - uses: actions/download-artifact@v3 - with: - name: samples-jacoco-result - path: dubbo-samples/target/ - - name: "Restore integration jacoco exec" - uses: actions/download-artifact@v3 + - name: "Restore integration test jacoco exec" + uses: actions/download-artifact@v4 with: - name: jacoco-result + pattern: jacoco-result-* + github-token: ${{ secrets.GITHUB_TOKEN }} path: dubbo-integration-cases/target/ - - name: "Merge jacoco result" - run: | - cd ${{ github.workspace }}/dubbo-samples/test/dubbo-test-jacoco-merger - mvn clean compile exec:java -Dexec.mainClass="org.apache.dubbo.test.JacocoReport" -Dexec.args="${{github.workspace}}/dubbo-samples ${{github.workspace}}/dubbo" - - name: "Merge samples jacoco result" + - name: "Merge integration test jacoco result" run: | cd ${{ github.workspace }}/dubbo-integration-cases/test/dubbo-test-jacoco-merger - mvn clean compile exec:java -Dexec.mainClass="org.apache.dubbo.test.JacocoReport" -Dexec.args="${{github.workspace}}/dubbo-integration-cases ${{github.workspace}}/dubbo" - - name: "Restore coverage result" - uses: actions/download-artifact@v3 - with: - name: coverage-result - path: dubbo/ + mvn clean compile exec:java -Dexec.mainClass="org.apache.dubbo.test.JacocoReport" -Dexec.args="${{github.workspace}}/dubbo-integration-cases ${{github.workspace}}" + - name: "Remove old test result" + run: | + rm -rf ${{ github.workspace }}/dubbo-integration-cases - name: "Upload coverage to Codecov" - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 with: + token: ${{ secrets.CODECOV_TOKEN }} + flags: integration-tests verbose: true + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + error-code-inspecting: needs: check-format runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: path: "./dubbo" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-test-tools' ref: main path: "./dubbo-test-tools" - name: "Set up JDK 21" - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 21 @@ -563,7 +602,7 @@ jobs: - name: "Upload error code inspection result" # always() should not be used here, since we don't need to handle the 'canceled' situation. if: ${{ success() || failure() }} - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: "error-inspection-result" path: ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector/error-inspection-result.txt @@ -572,10 +611,10 @@ jobs: needs: check-format runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: path: "./dubbo" - - name: "Setup GraalVM environment" + - name: "Set up GraalVM environment" uses: graalvm/setup-graalvm@v1 with: version: '22.3.0' @@ -583,7 +622,7 @@ jobs: components: 'native-image' github-token: ${{ secrets.GITHUB_TOKEN }} native-image-job-reports: 'true' - - name: "Setup Zookeeper environment" + - name: "Set up Zookeeper environment" run: | wget https://dlcdn.apache.org/zookeeper/zookeeper-3.8.4/apache-zookeeper-3.8.4-bin.tar.gz tar -zxvf apache-zookeeper-3.8.4-bin.tar.gz @@ -595,7 +634,7 @@ jobs: native-image --version - name: "Set current date as env variable" run: echo "TODAY=$(date +'%Y%m%d')" >> $GITHUB_ENV - - name: "Restore local maven repository cache" + - name: "Restore local Maven repository cache" uses: actions/cache/restore@v4 with: path: ~/.m2/repository @@ -607,14 +646,21 @@ jobs: run: | cd ${{ github.workspace }}/dubbo ./mvnw ${{ env.MAVEN_ARGS }} -T 2C clean install -P '!demo',skip-spotless -Dmaven.test.skip=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true - - name: "Compile and run Dubbo demo for native (Linux)" + - name: "Checkout dubbo-samples repository" + uses: actions/checkout@v4 + with: + repository: 'apache/dubbo-samples' + ref: master + path: "./dubbo-samples" + - name: "Compile and run Dubbo native image demo" run: | - cd ${{ github.workspace }}/dubbo/dubbo-demo/dubbo-demo-native/dubbo-demo-native-interface - MVNW="${{ github.workspace }}/dubbo/mvnw ${{ env.MAVEN_ARGS }} -T 2C -Dmaven.test.skip=true" - $MVNW clean install - cd ../dubbo-demo-native-provider - $MVNW clean package -P native native:compile - nohup ./target/dubbo-demo-native-provider & - cd ../dubbo-demo-native-consumer + MVNW="${{ github.workspace }}/dubbo-samples/mvnw ${{ env.MAVEN_ARGS }} -Dmaven.test.skip=true" + cd ${{ github.workspace }}/dubbo-samples/2-advanced/dubbo-samples-native-image/dubbo-samples-native-image-provider $MVNW clean package -P native native:compile - ./target/dubbo-demo-native-consumer + nohup ./target/dubbo-samples-native-image-provider & + sleep 10 + curl \ + --header "Content-Type: application/json" \ + --data '{"name":"Dubbo"}' \ + http://localhost:50052/org.apache.dubbo.nativeimage.DemoService/sayHello/ + diff --git a/.github/workflows/build-and-test-scheduled-3.1.yml b/.github/workflows/build-and-test-scheduled-3.1.yml index 54a2abda858..e237f428a87 100644 --- a/.github/workflows/build-and-test-scheduled-3.1.yml +++ b/.github/workflows/build-and-test-scheduled-3.1.yml @@ -24,7 +24,7 @@ jobs: license: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: "3.1" - name: Check License @@ -36,11 +36,11 @@ jobs: outputs: version: ${{ steps.dubbo-version.outputs.version }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: "3.1" path: dubbo - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 8 @@ -66,7 +66,7 @@ jobs: run: 7z a ${{ github.workspace }}/checkstyle.zip *checkstyle* -r - name: "Upload checkstyle file if failure" if: failure() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: "checkstyle-file" path: ${{ github.workspace }}/checkstyle.zip @@ -85,7 +85,7 @@ jobs: matrix: os: [ ubuntu-latest, windows-latest ] env: - ZOOKEEPER_VERSION: 3.6.3 + ZOOKEEPER_VERSION: 3.7.2 steps: - uses: actions/cache@v3 name: "Cache zookeeper binary archive" @@ -138,7 +138,7 @@ jobs: env: DISABLE_FILE_SYSTEM_TEST: true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: "3.1" - name: "Set up JDK ${{ matrix.jdk }}" @@ -184,9 +184,9 @@ jobs: DUBBO_DEFAULT_SERIALIZATION: fastjson2 MAVEN_SUREFIRE_ADD_OPENS: true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: "Set up JDK ${{ matrix.jdk }}" - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: ${{ matrix.jdk }} @@ -228,7 +228,7 @@ jobs: env: JOB_COUNT: 5 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-samples' ref: master @@ -236,7 +236,7 @@ jobs: run: | bash ./test/scripts/prepare-test.sh - name: "Upload test list" - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: samples-test-list path: test/jobs @@ -254,7 +254,7 @@ jobs: jdk: [ 8, 11 ] job_id: [1, 2, 3, 4, 5] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-samples' ref: master @@ -275,7 +275,7 @@ jobs: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }} ${{ runner.os }}-dubbo-snapshot- - name: "Download test list" - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: samples-test-list path: test/jobs/ @@ -295,9 +295,9 @@ jobs: run: cd test && bash ./run-tests.sh - name: "Upload test result" if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: samples-test-result-${{matrix.jdk}} + name: samples-test-result-${{matrix.job_id}} path: test/jobs/*-result* samples-test-result: needs: [samples-test-job] @@ -309,14 +309,15 @@ jobs: matrix: jdk: [ 8, 11 ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-samples' ref: master - name: "Download test result" - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: - name: samples-test-result-${{matrix.jdk}} + name: samples-test-result-* + github-token: ${{ secrets.GITHUB_TOKEN }} path: test/jobs/ - name: "Merge test result" run: ./test/scripts/merge-test-results.sh @@ -326,7 +327,7 @@ jobs: env: JOB_COUNT: 5 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-integration-cases' ref: main @@ -334,7 +335,7 @@ jobs: run: | bash ./test/scripts/prepare-test.sh - name: "Upload test list" - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: integration-test-list path: test/jobs @@ -352,7 +353,7 @@ jobs: jdk: [ 8, 11 ] job_id: [1, 2, 3, 4, 5] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-integration-cases' ref: main @@ -373,7 +374,7 @@ jobs: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }} ${{ runner.os }}-dubbo-snapshot- - name: "Download test list" - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: integration-test-list path: test/jobs/ @@ -393,9 +394,9 @@ jobs: run: cd test && bash ./run-tests.sh - name: "Upload test result" if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: integration-test-result-${{matrix.jdk}} + name: integration-test-result-${{matrix.job_id}} path: test/jobs/*-result* integration-test-result: needs: [integration-test-job] @@ -407,14 +408,15 @@ jobs: matrix: jdk: [ 8, 11 ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-integration-cases' ref: main - name: "Download test result" - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: - name: integration-test-result-${{matrix.jdk}} + name: integration-test-result-* + github-token: ${{ secrets.GITHUB_TOKEN }} path: test/jobs/ - name: "Merge test result" run: ./test/scripts/merge-test-results.sh @@ -422,19 +424,19 @@ jobs: error-code-inspecting: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: "3.1" path: "./dubbo" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-test-tools' ref: main path: "./dubbo-test-tools" - name: "Set up JDK 21" - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 21 @@ -453,7 +455,7 @@ jobs: - name: "Upload error code inspection result" # always() should not be used here, since we don't need to handle the 'canceled' situation. if: ${{ success() || failure() }} - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: "error-inspection-result" path: ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector/error-inspection-result.txt @@ -461,7 +463,7 @@ jobs: native-image-inspecting: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: "3.1" path: "./dubbo" diff --git a/.github/workflows/build-and-test-scheduled-3.2.yml b/.github/workflows/build-and-test-scheduled-3.2.yml index e3b3d95c8d5..370ce6d3b00 100644 --- a/.github/workflows/build-and-test-scheduled-3.2.yml +++ b/.github/workflows/build-and-test-scheduled-3.2.yml @@ -24,7 +24,7 @@ jobs: license: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: "3.2" - name: Check License @@ -36,11 +36,11 @@ jobs: outputs: version: ${{ steps.dubbo-version.outputs.version }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: "3.2" path: dubbo - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 8 @@ -66,7 +66,7 @@ jobs: run: 7z a ${{ github.workspace }}/checkstyle.zip *checkstyle* -r - name: "Upload checkstyle file if failure" if: failure() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: "checkstyle-file" path: ${{ github.workspace }}/checkstyle.zip @@ -85,7 +85,7 @@ jobs: matrix: os: [ ubuntu-latest, windows-latest ] env: - ZOOKEEPER_VERSION: 3.6.3 + ZOOKEEPER_VERSION: 3.7.2 steps: - uses: actions/cache@v3 name: "Cache zookeeper binary archive" @@ -138,7 +138,7 @@ jobs: env: DISABLE_FILE_SYSTEM_TEST: true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: "3.2" - name: "Set up JDK ${{ matrix.jdk }}" @@ -184,9 +184,9 @@ jobs: DUBBO_DEFAULT_SERIALIZATION: fastjson2 MAVEN_SUREFIRE_ADD_OPENS: true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: "Set up JDK ${{ matrix.jdk }}" - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: ${{ matrix.jdk }} @@ -228,7 +228,7 @@ jobs: env: JOB_COUNT: 5 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-samples' ref: master @@ -236,7 +236,7 @@ jobs: run: | bash ./test/scripts/prepare-test.sh - name: "Upload test list" - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: samples-test-list path: test/jobs @@ -254,7 +254,7 @@ jobs: jdk: [ 8, 11, 17, 21 ] job_id: [1, 2, 3, 4, 5] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-samples' ref: master @@ -275,7 +275,7 @@ jobs: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }} ${{ runner.os }}-dubbo-snapshot- - name: "Download test list" - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: samples-test-list path: test/jobs/ @@ -295,9 +295,9 @@ jobs: run: cd test && bash ./run-tests.sh - name: "Upload test result" if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: samples-test-result-${{matrix.jdk}} + name: samples-test-result-${{matrix.job_id}} path: test/jobs/*-result* samples-test-result: needs: [samples-test-job] @@ -309,14 +309,15 @@ jobs: matrix: jdk: [ 8, 11, 17, 21 ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-samples' ref: master - name: "Download test result" - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: - name: samples-test-result-${{matrix.jdk}} + name: samples-test-result-* + github-token: ${{ secrets.GITHUB_TOKEN }} path: test/jobs/ - name: "Merge test result" run: ./test/scripts/merge-test-results.sh @@ -326,7 +327,7 @@ jobs: env: JOB_COUNT: 5 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-integration-cases' ref: main @@ -334,7 +335,7 @@ jobs: run: | bash ./test/scripts/prepare-test.sh - name: "Upload test list" - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: integration-test-list path: test/jobs @@ -352,7 +353,7 @@ jobs: jdk: [ 8, 11, 17, 21 ] job_id: [1, 2, 3, 4, 5] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-integration-cases' ref: main @@ -373,7 +374,7 @@ jobs: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }} ${{ runner.os }}-dubbo-snapshot- - name: "Download test list" - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: integration-test-list path: test/jobs/ @@ -393,9 +394,9 @@ jobs: run: cd test && bash ./run-tests.sh - name: "Upload test result" if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: integration-test-result-${{matrix.jdk}} + name: integration-test-result-${{matrix.job_id}} path: test/jobs/*-result* integration-test-result: needs: [integration-test-job] @@ -407,14 +408,15 @@ jobs: matrix: jdk: [ 8, 11, 17, 21 ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-integration-cases' ref: main - name: "Download test result" - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: - name: integration-test-result-${{matrix.jdk}} + name: integration-test-result-* + github-token: ${{ secrets.GITHUB_TOKEN }} path: test/jobs/ - name: "Merge test result" run: ./test/scripts/merge-test-results.sh @@ -422,19 +424,19 @@ jobs: error-code-inspecting: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: "3.2" path: "./dubbo" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-test-tools' ref: main path: "./dubbo-test-tools" - name: "Set up JDK 21" - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 21 @@ -453,7 +455,7 @@ jobs: - name: "Upload error code inspection result" # always() should not be used here, since we don't need to handle the 'canceled' situation. if: ${{ success() || failure() }} - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: "error-inspection-result" path: ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector/error-inspection-result.txt @@ -461,7 +463,7 @@ jobs: native-image-inspecting: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: "3.2" path: "./dubbo" diff --git a/.github/workflows/build-and-test-scheduled-3.3.yml b/.github/workflows/build-and-test-scheduled-3.3.yml index 3240efb8f8a..76fc28eeb4b 100644 --- a/.github/workflows/build-and-test-scheduled-3.3.yml +++ b/.github/workflows/build-and-test-scheduled-3.3.yml @@ -24,7 +24,7 @@ jobs: license: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: "3.3" - name: Check License @@ -36,11 +36,11 @@ jobs: outputs: version: ${{ steps.dubbo-version.outputs.version }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: "3.3" path: dubbo - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 21 @@ -66,7 +66,7 @@ jobs: run: 7z a ${{ github.workspace }}/checkstyle.zip *checkstyle* -r - name: "Upload checkstyle file if failure" if: failure() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: "checkstyle-file" path: ${{ github.workspace }}/checkstyle.zip @@ -85,7 +85,7 @@ jobs: matrix: os: [ ubuntu-latest, windows-latest ] env: - ZOOKEEPER_VERSION: 3.6.3 + ZOOKEEPER_VERSION: 3.7.2 steps: - uses: actions/cache@v3 name: "Cache zookeeper binary archive" @@ -138,7 +138,7 @@ jobs: env: DISABLE_FILE_SYSTEM_TEST: true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: "3.3" - name: "Set up JDK ${{ matrix.jdk }}" @@ -184,9 +184,9 @@ jobs: DUBBO_DEFAULT_SERIALIZATION: fastjson2 MAVEN_SUREFIRE_ADD_OPENS: true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: "Set up JDK ${{ matrix.jdk }}" - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: ${{ matrix.jdk }} @@ -228,7 +228,7 @@ jobs: env: JOB_COUNT: 5 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-samples' ref: master @@ -236,7 +236,7 @@ jobs: run: | bash ./test/scripts/prepare-test.sh - name: "Upload test list" - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: samples-test-list path: test/jobs @@ -254,7 +254,7 @@ jobs: jdk: [ 8, 11, 17, 21 ] job_id: [1, 2, 3, 4, 5] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-samples' ref: master @@ -275,7 +275,7 @@ jobs: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }} ${{ runner.os }}-dubbo-snapshot- - name: "Download test list" - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: samples-test-list path: test/jobs/ @@ -295,9 +295,9 @@ jobs: run: cd test && bash ./run-tests.sh - name: "Upload test result" if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: samples-test-result-${{matrix.jdk}} + name: samples-test-result-${{matrix.job_id}} path: test/jobs/*-result* samples-test-result: needs: [samples-test-job] @@ -309,14 +309,15 @@ jobs: matrix: jdk: [ 8, 11, 17, 21 ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-samples' ref: master - name: "Download test result" - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: - name: samples-test-result-${{matrix.jdk}} + name: samples-test-result-* + github-token: ${{ secrets.GITHUB_TOKEN }} path: test/jobs/ - name: "Merge test result" run: ./test/scripts/merge-test-results.sh @@ -326,7 +327,7 @@ jobs: env: JOB_COUNT: 5 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-integration-cases' ref: main @@ -334,7 +335,7 @@ jobs: run: | bash ./test/scripts/prepare-test.sh - name: "Upload test list" - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: integration-test-list path: test/jobs @@ -352,7 +353,7 @@ jobs: jdk: [ 8, 11, 17, 21 ] job_id: [1, 2, 3, 4, 5] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-integration-cases' ref: main @@ -373,7 +374,7 @@ jobs: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }} ${{ runner.os }}-dubbo-snapshot- - name: "Download test list" - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: integration-test-list path: test/jobs/ @@ -393,9 +394,9 @@ jobs: run: cd test && bash ./run-tests.sh - name: "Upload test result" if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: integration-test-result-${{matrix.jdk}} + name: integration-test-result-${{matrix.job_id}} path: test/jobs/*-result* integration-test-result: needs: [integration-test-job] @@ -407,14 +408,15 @@ jobs: matrix: jdk: [ 8, 11, 17, 21 ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-integration-cases' ref: main - name: "Download test result" - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: - name: integration-test-result-${{matrix.jdk}} + name: integration-test-result-* + github-token: ${{ secrets.GITHUB_TOKEN }} path: test/jobs/ - name: "Merge test result" run: ./test/scripts/merge-test-results.sh @@ -422,19 +424,19 @@ jobs: error-code-inspecting: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: "3.3" path: "./dubbo" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-test-tools' ref: main path: "./dubbo-test-tools" - name: "Set up JDK 21" - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 21 @@ -453,7 +455,7 @@ jobs: - name: "Upload error code inspection result" # always() should not be used here, since we don't need to handle the 'canceled' situation. if: ${{ success() || failure() }} - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: "error-inspection-result" path: ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector/error-inspection-result.txt @@ -461,12 +463,10 @@ jobs: native-image-inspecting: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: - ref: "3.3" path: "./dubbo" - - - name: "Setup GraalVM environment" + - name: "Set up GraalVM environment" uses: graalvm/setup-graalvm@v1 with: version: '22.3.0' @@ -474,32 +474,44 @@ jobs: components: 'native-image' github-token: ${{ secrets.GITHUB_TOKEN }} native-image-job-reports: 'true' - - - name: "Setup Zookeeper environment" + - name: "Set up Zookeeper environment" run: | wget https://dlcdn.apache.org/zookeeper/zookeeper-3.8.4/apache-zookeeper-3.8.4-bin.tar.gz tar -zxvf apache-zookeeper-3.8.4-bin.tar.gz mv apache-zookeeper-3.8.4-bin/conf/zoo_sample.cfg apache-zookeeper-3.8.4-bin/conf/zoo.cfg apache-zookeeper-3.8.4-bin/bin/zkServer.sh start - - name: "Check environment" run: | java --version native-image --version - + - name: "Set current date as env variable" + run: echo "TODAY=$(date +'%Y%m%d')" >> $GITHUB_ENV + - name: "Restore local Maven repository cache" + uses: actions/cache/restore@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ env.TODAY }} + restore-keys: | + ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + ${{ runner.os }}-maven- - name: "Compile Dubbo (Linux)" run: | cd ${{ github.workspace }}/dubbo ./mvnw ${{ env.MAVEN_ARGS }} -T 2C clean install -P '!demo',skip-spotless -Dmaven.test.skip=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true - - - name: "Compile and run Dubbo demo for native (Linux)" + - name: "Checkout dubbo-samples repository" + uses: actions/checkout@v4 + with: + repository: 'apache/dubbo-samples' + ref: master + path: "./dubbo-samples" + - name: "Compile and run Dubbo native image demo" run: | - cd ${{ github.workspace }}/dubbo/dubbo-demo/dubbo-demo-native/dubbo-demo-native-interface - MVNW="${{ github.workspace }}/dubbo/mvnw ${{ env.MAVEN_ARGS }} -T 2C -Dmaven.test.skip=true" - $MVNW clean install - cd ../dubbo-demo-native-provider - $MVNW clean package -P native native:compile - nohup ./target/dubbo-demo-native-provider & - cd ../dubbo-demo-native-consumer + MVNW="${{ github.workspace }}/dubbo-samples/mvnw ${{ env.MAVEN_ARGS }} -Dmaven.test.skip=true" + cd ${{ github.workspace }}/dubbo-samples/2-advanced/dubbo-samples-native-image/dubbo-samples-native-image-provider $MVNW clean package -P native native:compile - ./target/dubbo-demo-native-consumer + nohup ./target/dubbo-samples-native-image-provider & + sleep 10 + curl \ + --header "Content-Type: application/json" \ + --data '{"name":"Dubbo"}' \ + http://localhost:50052/org.apache.dubbo.nativeimage.DemoService/sayHello/ diff --git a/.github/workflows/release-test.yml b/.github/workflows/release-test.yml index dea1cf2d4cf..4895593e9a7 100644 --- a/.github/workflows/release-test.yml +++ b/.github/workflows/release-test.yml @@ -25,7 +25,7 @@ jobs: license: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Check License uses: apache/skywalking-eyes@main env: @@ -35,10 +35,10 @@ jobs: outputs: version: ${{ steps.dubbo-version.outputs.version }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: path: dubbo - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: 21 @@ -64,7 +64,7 @@ jobs: run: 7z a ${{ github.workspace }}/checkstyle.zip *checkstyle* -r - name: "Upload checkstyle file if failure" if: failure() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: "checkstyle-file" path: ${{ github.workspace }}/checkstyle.zip @@ -83,7 +83,7 @@ jobs: matrix: os: [ ubuntu-latest, windows-latest ] env: - ZOOKEEPER_VERSION: 3.6.3 + ZOOKEEPER_VERSION: 3.7.2 steps: - uses: actions/cache@v3 name: "Cache zookeeper binary archive" @@ -136,9 +136,9 @@ jobs: env: DISABLE_FILE_SYSTEM_TEST: true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: "Set up JDK ${{ matrix.jdk }}" - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: ${{ matrix.jdk }} distribution: 'zulu' @@ -181,9 +181,9 @@ jobs: DUBBO_DEFAULT_SERIALIZATION: fastjson2 MAVEN_SUREFIRE_ADD_OPENS: true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: "Set up JDK ${{ matrix.jdk }}" - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: ${{ matrix.jdk }} @@ -225,7 +225,7 @@ jobs: env: JOB_COUNT: 5 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-samples' ref: master @@ -233,7 +233,7 @@ jobs: run: | bash ./test/scripts/prepare-test.sh - name: "Upload test list" - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: samples-test-list path: test/jobs @@ -251,7 +251,7 @@ jobs: jdk: [ 8, 11, 17, 21 ] job_id: [1, 2, 3, 4, 5] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-samples' ref: master @@ -272,7 +272,7 @@ jobs: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }} ${{ runner.os }}-dubbo-snapshot- - name: "Download test list" - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: samples-test-list path: test/jobs/ @@ -292,9 +292,9 @@ jobs: run: cd test && bash ./run-tests.sh - name: "Upload test result" if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: samples-test-result-${{matrix.jdk}} + name: samples-test-result-${{matrix.job_id}} path: test/jobs/*-result* samples-test-result: needs: [samples-test-job] @@ -306,14 +306,15 @@ jobs: matrix: jdk: [ 8, 11, 17, 21 ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-samples' ref: master - name: "Download test result" - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: - name: samples-test-result-${{matrix.jdk}} + name: samples-test-result-* + github-token: ${{ secrets.GITHUB_TOKEN }} path: test/jobs/ - name: "Merge test result" run: ./test/scripts/merge-test-results.sh @@ -323,7 +324,7 @@ jobs: env: JOB_COUNT: 5 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-integration-cases' ref: main @@ -331,7 +332,7 @@ jobs: run: | bash ./test/scripts/prepare-test.sh - name: "Upload test list" - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: integration-test-list path: test/jobs @@ -349,7 +350,7 @@ jobs: jdk: [ 8, 11, 17, 21 ] job_id: [1, 2, 3, 4, 5] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-integration-cases' ref: main @@ -370,7 +371,7 @@ jobs: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }} ${{ runner.os }}-dubbo-snapshot- - name: "Download test list" - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: integration-test-list path: test/jobs/ @@ -390,9 +391,9 @@ jobs: run: cd test && bash ./run-tests.sh - name: "Upload test result" if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: integration-test-result-${{matrix.jdk}} + name: integration-test-result-${{matrix.job_id}} path: test/jobs/*-result* integration-test-result: needs: [integration-test-job] @@ -404,14 +405,15 @@ jobs: matrix: jdk: [ 8, 11, 17, 21 ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-integration-cases' ref: main - name: "Download test result" - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: - name: integration-test-result-${{matrix.jdk}} + name: integration-test-result-* + github-token: ${{ secrets.GITHUB_TOKEN }} path: test/jobs/ - name: "Merge test result" run: ./test/scripts/merge-test-results.sh @@ -419,18 +421,18 @@ jobs: error-code-inspecting: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: path: "./dubbo" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: 'apache/dubbo-test-tools' ref: main path: "./dubbo-test-tools" - name: "Set up JDK 21" - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: 21 distribution: 'zulu' @@ -449,7 +451,7 @@ jobs: - name: "Upload error code inspection result" # always() should not be used here, since we don't need to handle the 'canceled' situation. if: ${{ success() || failure() }} - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: "error-inspection-result" path: ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector/error-inspection-result.txt @@ -457,11 +459,10 @@ jobs: native-image-inspecting: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: path: "./dubbo" - - - name: "Setup GraalVM environment" + - name: "Set up GraalVM environment" uses: graalvm/setup-graalvm@v1 with: version: '22.3.0' @@ -469,32 +470,44 @@ jobs: components: 'native-image' github-token: ${{ secrets.GITHUB_TOKEN }} native-image-job-reports: 'true' - - - name: "Setup Zookeeper environment" + - name: "Set up Zookeeper environment" run: | wget https://dlcdn.apache.org/zookeeper/zookeeper-3.8.4/apache-zookeeper-3.8.4-bin.tar.gz tar -zxvf apache-zookeeper-3.8.4-bin.tar.gz mv apache-zookeeper-3.8.4-bin/conf/zoo_sample.cfg apache-zookeeper-3.8.4-bin/conf/zoo.cfg apache-zookeeper-3.8.4-bin/bin/zkServer.sh start - - name: "Check environment" run: | java --version native-image --version - + - name: "Set current date as env variable" + run: echo "TODAY=$(date +'%Y%m%d')" >> $GITHUB_ENV + - name: "Restore local Maven repository cache" + uses: actions/cache/restore@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ env.TODAY }} + restore-keys: | + ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + ${{ runner.os }}-maven- - name: "Compile Dubbo (Linux)" run: | cd ${{ github.workspace }}/dubbo ./mvnw ${{ env.MAVEN_ARGS }} -T 2C clean install -P '!demo',skip-spotless -Dmaven.test.skip=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true - - - name: "Compile and run Dubbo demo for native (Linux)" + - name: "Checkout dubbo-samples repository" + uses: actions/checkout@v4 + with: + repository: 'apache/dubbo-samples' + ref: master + path: "./dubbo-samples" + - name: "Compile and run Dubbo native image demo" run: | - cd ${{ github.workspace }}/dubbo/dubbo-demo/dubbo-demo-native/dubbo-demo-native-interface - MVNW="${{ github.workspace }}/dubbo/mvnw ${{ env.MAVEN_ARGS }} -T 2C -Dmaven.test.skip=true" - $MVNW clean install - cd ../dubbo-demo-native-provider - $MVNW clean package -P native native:compile - nohup ./target/dubbo-demo-native-provider & - cd ../dubbo-demo-native-consumer + MVNW="${{ github.workspace }}/dubbo-samples/mvnw ${{ env.MAVEN_ARGS }} -Dmaven.test.skip=true" + cd ${{ github.workspace }}/dubbo-samples/2-advanced/dubbo-samples-native-image/dubbo-samples-native-image-provider $MVNW clean package -P native native:compile - ./target/dubbo-demo-native-consumer + nohup ./target/dubbo-samples-native-image-provider & + sleep 10 + curl \ + --header "Content-Type: application/json" \ + --data '{"name":"Dubbo"}' \ + http://localhost:50052/org.apache.dubbo.nativeimage.DemoService/sayHello/ diff --git a/LICENSE b/LICENSE index b2d3628b89d..3716d3930ed 100644 --- a/LICENSE +++ b/LICENSE @@ -287,3 +287,11 @@ This product contains a modified portion of 'Istio', an open platform to connect under a "Apache License 2.0" license, see https://github.com/istio/api/blob/master/LICENSE: * security/v1alpha1/ca.proto + +For the file dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/resources/swagger-ui/index.html: + +Under a "Apache License 2.0" license, see https://github.com/swagger-api/swagger-ui/blob/master/LICENSE + +For the file dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/resources/redoc/index.html: + +Under a "MIT License" license, see https://github.com/Redocly/redoc/blob/main/LICENSE diff --git a/codecov.yml b/codecov.yml index 594d03079be..c266ead21ce 100644 --- a/codecov.yml +++ b/codecov.yml @@ -24,10 +24,10 @@ coverage: default: threshold: 0.1% ignore: - - "**/dubbo-demo/**" - - "**/dubbo-compiler/**" - - "**/dubbo-test/**" - - "**/dubbo-compatible/**" - - "**/dubbo-native/**" - - "**/dubbo-common/src/main/java/org/apache/dubbo/common/json/*.java" # internal JSON impl is deprecate, ignore test coverage for them - - "**/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/AnnotationBean.java" # Deprecated + - "**/aot/**/*" + - "dubbo-demo/**/*" + - "dubbo-compiler/**/*" + - "dubbo-test/**/*" + - "dubbo-compatible/**/*" + - "dubbo-native/**/*" + - "dubbo-maven-plugin/**/*" diff --git a/dubbo-cluster/pom.xml b/dubbo-cluster/pom.xml index f5136d52cfe..3a0e67b62a6 100644 --- a/dubbo-cluster/pom.xml +++ b/dubbo-cluster/pom.xml @@ -47,16 +47,6 @@ ${project.parent.version} test - - org.apache.curator - curator-framework - test - - - org.apache.zookeeper - zookeeper - test - org.apache.dubbo dubbo-serialization-hessian2 @@ -69,12 +59,6 @@ ${project.parent.version} test - - org.apache.dubbo - dubbo-test-check - ${project.parent.version} - test - org.apache.dubbo dubbo-metrics-registry diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ClusterScopeModelInitializer.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ClusterScopeModelInitializer.java index fb9d23b0c3f..52548da6c0b 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ClusterScopeModelInitializer.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ClusterScopeModelInitializer.java @@ -21,10 +21,10 @@ import org.apache.dubbo.rpc.cluster.support.ClusterUtils; import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; public class ClusterScopeModelInitializer implements ScopeModelInitializer { + @Override public void initializeFrameworkModel(FrameworkModel frameworkModel) { ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory(); @@ -36,7 +36,4 @@ public void initializeApplicationModel(ApplicationModel applicationModel) { ScopeBeanFactory beanFactory = applicationModel.getBeanFactory(); beanFactory.registerBean(ClusterUtils.class); } - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/MergeableClusterScopeModelInitializer.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/MergeableClusterScopeModelInitializer.java index 1788e4d4ed8..288ea4a6117 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/MergeableClusterScopeModelInitializer.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/MergeableClusterScopeModelInitializer.java @@ -19,20 +19,13 @@ import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; import org.apache.dubbo.rpc.cluster.merger.MergerFactory; import org.apache.dubbo.rpc.model.ApplicationModel; -import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; public class MergeableClusterScopeModelInitializer implements ScopeModelInitializer { - @Override - public void initializeFrameworkModel(FrameworkModel frameworkModel) {} @Override public void initializeApplicationModel(ApplicationModel applicationModel) { ScopeBeanFactory beanFactory = applicationModel.getBeanFactory(); beanFactory.registerBean(MergerFactory.class); } - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/MeshScopeModelInitializer.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/MeshScopeModelInitializer.java index 6753f9b8e42..12bbc7dcf23 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/MeshScopeModelInitializer.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/MeshScopeModelInitializer.java @@ -18,17 +18,10 @@ import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; import org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleManager; -import org.apache.dubbo.rpc.model.ApplicationModel; -import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; public class MeshScopeModelInitializer implements ScopeModelInitializer { - @Override - public void initializeFrameworkModel(FrameworkModel frameworkModel) {} - - @Override - public void initializeApplicationModel(ApplicationModel applicationModel) {} public void initializeModuleModel(ModuleModel moduleModel) { ScopeBeanFactory beanFactory = moduleModel.getBeanFactory(); diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/ConfigConditionRouterTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/ConfigConditionRouterTest.java deleted file mode 100644 index 5290fc65a10..00000000000 --- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/ConfigConditionRouterTest.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.dubbo.rpc.cluster.router; - -import org.apache.curator.framework.CuratorFramework; -import org.apache.curator.framework.CuratorFrameworkFactory; -import org.apache.curator.retry.ExponentialBackoffRetry; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -@Disabled("FIXME This is not a formal UT") -class ConfigConditionRouterTest { - private static CuratorFramework client; - - @BeforeEach - public void init() { - client = CuratorFrameworkFactory.newClient( - "127.0.0.1:2181", 60 * 1000, 60 * 1000, new ExponentialBackoffRetry(1000, 3)); - client.start(); - } - - @Test - void normalConditionRuleApplicationLevelTest() { - String serviceStr = "---\n" + "scope: application\n" - + "force: true\n" - + "runtime: true\n" - + "enabled: true\n" - + "priority: 2\n" - + "key: demo-consumer\n" - + "conditions:\n" - + " - method=notExitMethod => \n" - + "..."; - try { - String servicePath = "/dubbo/config/demo-consumer/condition-router"; - if (client.checkExists().forPath(servicePath) == null) { - client.create().creatingParentsIfNeeded().forPath(servicePath); - } - setData(servicePath, serviceStr); - } catch (Exception e) { - e.printStackTrace(); - } - } - - @Test - void normalConditionRuleApplicationServiceLevelTest() { - String serviceStr = "---\n" + "scope: application\n" - + "force: true\n" - + "runtime: false\n" - + "enabled: true\n" - + "priority: 2\n" - + "key: demo-consumer\n" - + "conditions:\n" - + " - interface=org.apache.dubbo.demo.DemoService&method=sayHello => host=30.5.120.37\n" - + " - method=routeMethod1 => host=30.5.120.37\n" - + "..."; - try { - String servicePath = "/dubbo/config/demo-consumer/condition-router"; - if (client.checkExists().forPath(servicePath) == null) { - client.create().creatingParentsIfNeeded().forPath(servicePath); - } - setData(servicePath, serviceStr); - } catch (Exception e) { - e.printStackTrace(); - } - } - - @Test - void normalConditionRuleServiceLevelTest() { - String serviceStr = "---\n" + "scope: service\n" - + "force: true\n" - + "runtime: true\n" - + "enabled: true\n" - + "priority: 1\n" - + "key: org.apache.dubbo.demo.DemoService\n" - + "conditions:\n" - + " - method!=sayHello =>\n" - + " - method=routeMethod1 => address=30.5.120.37:20880\n" - + "..."; - // String serviceStr = ""; - try { - String servicePath = "/dubbo/config/org.apache.dubbo.demo.DemoService/condition-router"; - if (client.checkExists().forPath(servicePath) == null) { - client.create().creatingParentsIfNeeded().forPath(servicePath); - } - setData(servicePath, serviceStr); - } catch (Exception e) { - e.printStackTrace(); - } - } - - @Test - void abnormalNoruleConditionRuleTest() { - String serviceStr = "---\n" + "scope: service\n" - + "force: true\n" - + "runtime: false\n" - + "enabled: true\n" - + "priority: 1\n" - + "key: org.apache.dubbo.demo.DemoService\n" - + "..."; - try { - String servicePath = "/dubbo/config/org.apache.dubbo.demo.DemoService/condition-router"; - if (client.checkExists().forPath(servicePath) == null) { - client.create().creatingParentsIfNeeded().forPath(servicePath); - } - setData(servicePath, serviceStr); - } catch (Exception e) { - e.printStackTrace(); - } - } - - private void setData(String path, String data) throws Exception { - client.setData().forPath(path, data.getBytes()); - } -} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/ProtocolServiceKey.java b/dubbo-common/src/main/java/org/apache/dubbo/common/ProtocolServiceKey.java index e4f5862c028..672ee8184a7 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/ProtocolServiceKey.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/ProtocolServiceKey.java @@ -90,7 +90,7 @@ public static boolean isMatch(ProtocolServiceKey rule, ProtocolServiceKey target } // 4.match protocol - // 4.1. if rule group is *, match all + // 4.1. if rule protocol is *, match all if (!CommonConstants.ANY_VALUE.equals(rule.getProtocol())) { // 4.2. if rule protocol is null, match all if (StringUtils.isNotEmpty(rule.getProtocol())) { diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/beans/factory/ScopeBeanFactory.java b/dubbo-common/src/main/java/org/apache/dubbo/common/beans/factory/ScopeBeanFactory.java index b02d4c97fe4..db766dd0607 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/beans/factory/ScopeBeanFactory.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/beans/factory/ScopeBeanFactory.java @@ -24,10 +24,12 @@ import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.resource.Disposable; +import org.apache.dubbo.common.resource.Initializable; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.ConcurrentHashSet; import org.apache.dubbo.common.utils.Pair; import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.common.utils.TypeUtils; import org.apache.dubbo.rpc.model.ScopeModelAccessor; import java.util.ArrayList; @@ -39,6 +41,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; +import java.util.function.Supplier; import java.util.stream.Collectors; import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_DESTROY_INVOKER; @@ -55,6 +58,7 @@ public final class ScopeBeanFactory { private final List extensionPostProcessors; private final Map, AtomicInteger> beanNameIdCounterMap = CollectionUtils.newConcurrentHashMap(); private final List registeredBeanInfos = new CopyOnWriteArrayList<>(); + private final List> registeredBeanDefinitions = new CopyOnWriteArrayList<>(); private InstantiationStrategy instantiationStrategy; private final AtomicBoolean destroyed = new AtomicBoolean(); private final Set> registeredClasses = new ConcurrentHashSet<>(); @@ -79,14 +83,35 @@ private void initInstantiationStrategy() { } } - public T registerBean(Class bean) throws ScopeBeanException { - return getOrRegisterBean(null, bean); + public T registerBean(Class clazz) throws ScopeBeanException { + return getOrRegisterBean(null, clazz); } public T registerBean(String name, Class clazz) throws ScopeBeanException { return getOrRegisterBean(name, clazz); } + public void registerBeanDefinition(Class clazz) { + registerBeanDefinition(null, clazz); + } + + public void registerBeanDefinition(String name, Class clazz) { + registeredBeanDefinitions.add(new BeanDefinition<>(name, clazz)); + } + + public void registerBeanFactory(Supplier factory) { + registerBeanFactory(null, factory); + } + + @SuppressWarnings("unchecked") + public void registerBeanFactory(String name, Supplier factory) { + Class clazz = (Class) TypeUtils.getSuperGenericType(factory.getClass(), 0); + if (clazz == null) { + throw new ScopeBeanException("unable to determine bean class from factory's superclass or interface"); + } + registeredBeanDefinitions.add(new BeanDefinition<>(name, clazz, factory)); + } + private T createAndRegisterBean(String name, Class clazz) { checkDestroyed(); T instance = getBean(name, clazz); @@ -174,6 +199,9 @@ private void initializeBean(String name, Object bean) { for (ExtensionPostProcessor processor : extensionPostProcessors) { processor.postProcessAfterInitialization(bean, name); } + if (bean instanceof Initializable) { + ((Initializable) bean).initialize(extensionAccessor); + } } catch (Exception e) { throw new ScopeBeanException( "register bean failed! name=" + name + ", type=" @@ -182,9 +210,48 @@ private void initializeBean(String name, Object bean) { } } + @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter") + private void initializeBeanDefinitions(Class type) { + for (int i = 0, size = registeredBeanDefinitions.size(); i < size; i++) { + BeanDefinition definition = registeredBeanDefinitions.get(i); + if (definition.initialized) { + continue; + } + + Class beanClass = definition.beanClass; + if (!type.isAssignableFrom(beanClass)) { + continue; + } + synchronized (type) { + if (definition.initialized) { + continue; + } + + Object bean; + Supplier factory = definition.beanFactory; + if (factory == null) { + try { + bean = instantiationStrategy.instantiate(beanClass); + } catch (Throwable e) { + throw new ScopeBeanException("create bean instance failed, type=" + beanClass.getName(), e); + } + } else { + initializeBean(definition.name, factory); + try { + bean = factory.get(); + } catch (Exception e) { + throw new ScopeBeanException("create bean instance failed, type=" + beanClass.getName(), e); + } + } + registerBean(definition.name, bean); + definition.initialized = true; + } + } + } + private boolean containsBean(String name, Object bean) { for (BeanInfo beanInfo : registeredBeanInfos) { - if (beanInfo.instance == bean && (name == null || StringUtils.isEquals(name, beanInfo.name))) { + if (beanInfo.instance == bean && (name == null || name.equals(beanInfo.name))) { return true; } } @@ -199,6 +266,7 @@ private int getNextId(Class beanClass) { @SuppressWarnings("unchecked") public List getBeansOfType(Class type) { + initializeBeanDefinitions(type); List currentBeans = (List) registeredBeanInfos.stream() .filter(beanInfo -> type.isInstance(beanInfo.instance)) .map(beanInfo -> beanInfo.instance) @@ -223,19 +291,23 @@ public T getBean(String name, Class type) { @SuppressWarnings("unchecked") private T getBeanFromCache(String name, Class type) { - Object value = beanCache - .computeIfAbsent(Pair.of(type, name), k -> { - try { - return Optional.ofNullable(getBeanInternal(name, type)); - } catch (ScopeBeanException e) { - return Optional.of(e); - } - }) - .orElse(null); - if (value instanceof ScopeBeanException) { - throw (ScopeBeanException) value; + Pair, String> key = Pair.of(type, name); + Optional value = beanCache.get(key); + if (value == null) { + initializeBeanDefinitions(type); + value = beanCache.computeIfAbsent(key, k -> { + try { + return Optional.ofNullable(getBeanInternal(name, type)); + } catch (ScopeBeanException e) { + return Optional.of(e); + } + }); + } + Object bean = value.orElse(null); + if (bean instanceof ScopeBeanException) { + throw (ScopeBeanException) bean; } - return (T) value; + return (T) bean; } @SuppressWarnings("unchecked") @@ -301,6 +373,7 @@ public void destroy() { } } registeredBeanInfos.clear(); + registeredBeanDefinitions.clear(); beanCache.clear(); } } @@ -315,16 +388,36 @@ private void checkDestroyed() { } } - static class BeanInfo { + static final class BeanInfo { private final String name; private final Object instance; - public BeanInfo(String name, Object instance) { + BeanInfo(String name, Object instance) { this.name = name; this.instance = instance; } } + static final class BeanDefinition { + + private final String name; + private final Class beanClass; + private final Supplier beanFactory; + private volatile boolean initialized; + + BeanDefinition(String name, Class beanClass) { + this.name = name; + this.beanClass = beanClass; + beanFactory = null; + } + + BeanDefinition(String name, Class beanClass, Supplier beanFactory) { + this.name = name; + this.beanClass = beanClass; + this.beanFactory = beanFactory; + } + } + public Set> getRegisteredClasses() { return registeredClasses; } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/AdaptiveClassCodeGenerator.java b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/AdaptiveClassCodeGenerator.java index fd51fa15cc5..75977379de3 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/AdaptiveClassCodeGenerator.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/AdaptiveClassCodeGenerator.java @@ -224,37 +224,36 @@ private String generateUrlNullCheck(int index) { */ private String generateMethodContent(Method method) { Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class); - StringBuilder code = new StringBuilder(512); if (adaptiveAnnotation == null) { return generateUnsupported(method); - } else { - int urlTypeIndex = getUrlTypeIndex(method); + } + StringBuilder code = new StringBuilder(512); + int urlTypeIndex = getUrlTypeIndex(method); - // found parameter in URL type - if (urlTypeIndex != -1) { - // Null Point check - code.append(generateUrlNullCheck(urlTypeIndex)); - } else { - // did not find parameter in URL type - code.append(generateUrlAssignmentIndirectly(method)); - } + // found parameter in URL type + if (urlTypeIndex != -1) { + // Null Point check + code.append(generateUrlNullCheck(urlTypeIndex)); + } else { + // did not find parameter in URL type + code.append(generateUrlAssignmentIndirectly(method)); + } - String[] value = getMethodAdaptiveValue(adaptiveAnnotation); + String[] value = getMethodAdaptiveValue(adaptiveAnnotation); - boolean hasInvocation = hasInvocationArgument(method); + boolean hasInvocation = hasInvocationArgument(method); - code.append(generateInvocationArgumentNullCheck(method)); + code.append(generateInvocationArgumentNullCheck(method)); - code.append(generateExtNameAssignment(value, hasInvocation)); - // check extName == null? - code.append(generateExtNameNullCheck(value)); + code.append(generateExtNameAssignment(value, hasInvocation)); + // check extName == null? + code.append(generateExtNameNullCheck(value)); - code.append(generateScopeModelAssignment()); - code.append(generateExtensionAssignment()); + code.append(generateScopeModelAssignment()); + code.append(generateExtensionAssignment()); - // return statement - code.append(generateReturnAndInvocation(method)); - } + // return statement + code.append(generateReturnAndInvocation(method)); return code.toString(); } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/json/impl/JacksonImpl.java b/dubbo-common/src/main/java/org/apache/dubbo/common/json/impl/JacksonImpl.java index 449d0c0d839..d58a6ef64c2 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/json/impl/JacksonImpl.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/json/impl/JacksonImpl.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.extension.Activate; import java.lang.reflect.Type; +import java.util.ArrayList; import java.util.List; import com.fasterxml.jackson.annotation.JsonInclude.Include; @@ -26,6 +27,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.Module; import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.databind.json.JsonMapper.Builder; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; @@ -34,6 +36,7 @@ public class JacksonImpl extends AbstractJsonUtilImpl { private volatile JsonMapper mapper; + private final List customModules = new ArrayList<>(); @Override public String getName() { @@ -113,10 +116,24 @@ protected JsonMapper getMapper() { } protected Builder createBuilder() { - return JsonMapper.builder() + Builder builder = JsonMapper.builder() .configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true) .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) .serializationInclusion(Include.NON_NULL) .addModule(new JavaTimeModule()); + + for (Module module : customModules) { + builder.addModule(module); + } + + return builder; + } + + public void addModule(Module module) { + synchronized (this) { + customModules.add(module); + // Invalidate the mapper to rebuild it + this.mapper = null; + } } } diff --git a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/GreetingService.java b/dubbo-common/src/main/java/org/apache/dubbo/common/resource/Initializable.java similarity index 73% rename from dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/GreetingService.java rename to dubbo-common/src/main/java/org/apache/dubbo/common/resource/Initializable.java index 38c7a6072d1..6ba121f88ac 100644 --- a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/GreetingService.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/resource/Initializable.java @@ -14,11 +14,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.demo; +package org.apache.dubbo.common.resource; + +import org.apache.dubbo.common.extension.ExtensionAccessor; /** - * + * An interface for Initializing resources */ -public interface GreetingService { - String hello(); +public interface Initializable { + + default void initialize(ExtensionAccessor accessor) { + initialize(); + } + + default void initialize() {} } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassUtils.java index 52cb2782fd5..96442b0c05a 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassUtils.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.common.utils; +import org.apache.dubbo.common.constants.CommonConstants; import org.apache.dubbo.common.convert.ConverterUtil; import org.apache.dubbo.rpc.model.FrameworkModel; @@ -670,4 +671,8 @@ public static String[] getDeclaredMethodNames(Class tClass) { dmns.sort(Comparator.naturalOrder()); return dmns.toArray(new String[0]); } + + public static boolean hasProtobuf() { + return isPresent(CommonConstants.PROTOBUF_MESSAGE_CLASS_NAME); + } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DefaultParameterNameReader.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DefaultParameterNameReader.java new file mode 100644 index 00000000000..48c7f702584 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DefaultParameterNameReader.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.dubbo.common.utils; + +import org.apache.dubbo.rpc.model.FrameworkModel; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public final class DefaultParameterNameReader implements ParameterNameReader { + + private final Map> cache = CollectionUtils.newConcurrentHashMap(); + private final List readers; + + public DefaultParameterNameReader(FrameworkModel frameworkModel) { + readers = frameworkModel.getActivateExtensions(ParameterNameReader.class); + } + + @Override + public String[] readParameterNames(Method method) { + return cache.computeIfAbsent(method, k -> { + String[] names = readByReflection(method.getParameters()); + if (names == null) { + for (ParameterNameReader reader : readers) { + names = reader.readParameterNames(method); + if (names != null) { + break; + } + } + } + return Optional.ofNullable(names); + }) + .orElse(null); + } + + @Override + public String[] readParameterNames(Constructor ctor) { + return cache.computeIfAbsent(ctor, k -> { + String[] names = readByReflection(ctor.getParameters()); + if (names == null) { + for (ParameterNameReader reader : readers) { + names = reader.readParameterNames(ctor); + if (names != null) { + break; + } + } + } + return Optional.ofNullable(names); + }) + .orElse(null); + } + + private static String[] readByReflection(Parameter[] parameters) { + int len = parameters.length; + if (len == 0) { + return StringUtils.EMPTY_STRING_ARRAY; + } + String[] names = new String[len]; + for (int i = 0; i < len; i++) { + Parameter param = parameters[i]; + if (!param.isNamePresent()) { + return null; + } + names[i] = param.getName(); + } + return names; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/JavassistParameterNameReader.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/JavassistParameterNameReader.java new file mode 100644 index 00000000000..a640754e734 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/JavassistParameterNameReader.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.dubbo.common.utils; + +import org.apache.dubbo.common.constants.LoggerCodeConstants; +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Map; +import javassist.ClassPool; +import javassist.CtBehavior; +import javassist.CtConstructor; +import javassist.CtMethod; +import javassist.LoaderClassPath; +import javassist.bytecode.CodeAttribute; +import javassist.bytecode.Descriptor; +import javassist.bytecode.LocalVariableAttribute; + +import static org.apache.dubbo.common.logger.LoggerFactory.getErrorTypeAwareLogger; + +@Activate(order = 100, onClass = "javassist.ClassPool") +public class JavassistParameterNameReader implements ParameterNameReader { + + private static final ErrorTypeAwareLogger LOG = getErrorTypeAwareLogger(JavassistParameterNameReader.class); + + private final Map classPoolMap = CollectionUtils.newConcurrentHashMap(); + + @Override + public String[] readParameterNames(Method method) { + try { + Class[] paramTypes = method.getParameterTypes(); + if (paramTypes.length == 0) { + return StringUtils.EMPTY_STRING_ARRAY; + } + String descriptor = getDescriptor(paramTypes, method.getReturnType()); + Class clazz = method.getDeclaringClass(); + CtMethod ctMethod = getClassPool(clazz).get(clazz.getName()).getMethod(method.getName(), descriptor); + return read(ctMethod, Modifier.isStatic(method.getModifiers()) ? 0 : 1, paramTypes.length); + } catch (Throwable t) { + LOG.warn(LoggerCodeConstants.INTERNAL_ERROR, "", "", "Read parameter names error", t); + return null; + } + } + + @Override + public String[] readParameterNames(Constructor ctor) { + try { + Class[] paramTypes = ctor.getParameterTypes(); + if (paramTypes.length == 0) { + return StringUtils.EMPTY_STRING_ARRAY; + } + String descriptor = getDescriptor(paramTypes, void.class); + Class clazz = ctor.getDeclaringClass(); + CtConstructor ctCtor = getClassPool(clazz).get(clazz.getName()).getConstructor(descriptor); + return read(ctCtor, 1, paramTypes.length); + } catch (Throwable t) { + LOG.warn(LoggerCodeConstants.INTERNAL_ERROR, "", "", "Read parameter names error", t); + return null; + } + } + + private static String getDescriptor(Class[] parameterTypes, Class returnType) { + StringBuilder descriptor = new StringBuilder(32); + descriptor.append('('); + for (Class type : parameterTypes) { + descriptor.append(toJvmName(type)); + } + descriptor.append(')'); + descriptor.append(toJvmName(returnType)); + return descriptor.toString(); + } + + private static String toJvmName(Class clazz) { + return clazz.isArray() ? Descriptor.toJvmName(clazz.getName()) : Descriptor.of(clazz.getName()); + } + + private ClassPool getClassPool(Class clazz) { + ClassLoader classLoader = ClassUtils.getClassLoader(clazz); + return classPoolMap.computeIfAbsent(System.identityHashCode(classLoader), k -> { + ClassPool pool = new ClassPool(); + pool.appendClassPath(new LoaderClassPath(classLoader)); + return pool; + }); + } + + private static String[] read(CtBehavior behavior, int start, int len) { + if (behavior == null) { + return null; + } + CodeAttribute codeAttr = behavior.getMethodInfo().getCodeAttribute(); + if (codeAttr == null) { + return null; + } + LocalVariableAttribute attr = (LocalVariableAttribute) codeAttr.getAttribute(LocalVariableAttribute.tag); + if (attr == null) { + return null; + } + String[] names = new String[len]; + for (int i = 0, tLen = attr.tableLength(); i < tLen; i++) { + int j = attr.index(i) - start; + if (j >= 0 && j < len) { + names[j] = attr.variableName(i); + } + } + + return names; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LockUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LockUtils.java index f441dc9b2f0..4ffff0ea08d 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LockUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/LockUtils.java @@ -31,18 +31,24 @@ public class LockUtils { public static void safeLock(Lock lock, int timeout, Runnable runnable) { try { - if (!lock.tryLock(timeout, TimeUnit.MILLISECONDS)) { - logger.error( - LoggerCodeConstants.INTERNAL_ERROR, - "", - "", - "Try to lock failed, timeout: " + timeout, - new TimeoutException()); + boolean interrupted = false; + try { + if (!lock.tryLock(timeout, TimeUnit.MILLISECONDS)) { + logger.error( + LoggerCodeConstants.INTERNAL_ERROR, + "", + "", + "Try to lock failed, timeout: " + timeout, + new TimeoutException()); + } + } catch (InterruptedException e) { + logger.warn(LoggerCodeConstants.INTERNAL_ERROR, "", "", "Try to lock failed", e); + interrupted = true; } runnable.run(); - } catch (InterruptedException e) { - logger.warn(LoggerCodeConstants.INTERNAL_ERROR, "", "", "Try to lock failed", e); - Thread.currentThread().interrupt(); + if (interrupted) { + Thread.currentThread().interrupt(); + } } finally { try { lock.unlock(); diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-consumer/src/main/java/org/apache/dubbo/demo/rest/api/consumer/SpringRestDemoServiceConsumer.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ParameterNameReader.java similarity index 67% rename from dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-consumer/src/main/java/org/apache/dubbo/demo/rest/api/consumer/SpringRestDemoServiceConsumer.java rename to dubbo-common/src/main/java/org/apache/dubbo/common/utils/ParameterNameReader.java index fbedf5decde..7cb1f51fafb 100644 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-consumer/src/main/java/org/apache/dubbo/demo/rest/api/consumer/SpringRestDemoServiceConsumer.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ParameterNameReader.java @@ -14,15 +14,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.demo.rest.api.consumer; +package org.apache.dubbo.common.utils; -import org.apache.dubbo.config.annotation.DubboReference; -import org.apache.dubbo.demo.rest.api.SpringRestDemoService; +import org.apache.dubbo.common.extension.ExtensionScope; +import org.apache.dubbo.common.extension.SPI; -import org.springframework.stereotype.Component; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; -@Component -public class SpringRestDemoServiceConsumer { - @DubboReference(interfaceClass = SpringRestDemoService.class) - SpringRestDemoService springRestDemoService; +@SPI(scope = ExtensionScope.FRAMEWORK) +public interface ParameterNameReader { + + String[] readParameterNames(Method method); + + String[] readParameterNames(Constructor ctor); } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java index 74786e8a2e1..78ee6f5530d 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java @@ -1265,12 +1265,17 @@ public static boolean startsWithIgnoreCase(String str, String prefix) { return str.regionMatches(true, 0, prefix, 0, prefix.length()); } + /** + * Returns the default string if the input string is empty, otherwise returns + * the input string itself + */ public static String defaultIf(String str, String defaultStr) { return isEmpty(str) ? defaultStr : str; } /** - * Returns a substring from 'str' between 'start' and 'end', or to the end if 'end' is -1 + * Gets a substring from the specified String avoiding exceptions. If end index + * is not found, returns substring from start to the end */ public static String substring(String str, int start, int end) { if (str == null) { @@ -1280,8 +1285,8 @@ public static String substring(String str, int start, int end) { } /** - * Extracts a substring from the given string that precedes the first occurrence of the specified character separator. - * If the character is not found, the entire string is returned. + * Gets the substring before the first occurrence of a separator. + *

If nothing is found, returns the original string

*/ public static String substringBefore(String str, int separator) { if (isEmpty(str)) { @@ -1292,20 +1297,41 @@ public static String substringBefore(String str, int separator) { } /** - * Extracts a substring from the given string that precedes the first occurrence of the specified string separator. - * If the separator is not found or is null, the entire string is returned. + * Gets the substring after the first occurrence of a separator. + *

If nothing is found, the empty string is returned.

*/ - public static String substringBefore(String str, String separator) { - if (isEmpty(str) || separator == null) { + public static String substringAfter(String str, int separator) { + if (isEmpty(str)) { return str; } - if (separator.isEmpty()) { - return EMPTY_STRING; - } int index = str.indexOf(separator); + return index == INDEX_NOT_FOUND ? str : str.substring(index + 1); + } + + /** + * Gets the substring before the last occurrence of a separator. + *

If nothing is found, returns the original string

+ */ + public static String substringBeforeLast(String str, int separator) { + if (isEmpty(str)) { + return str; + } + int index = str.lastIndexOf(separator); return index == INDEX_NOT_FOUND ? str : str.substring(0, index); } + /** + * Gets the substring after the last occurrence of a separator. + *

If nothing is found, the empty string is returned.

+ */ + public static String substringAfterLast(String str, int separator) { + if (isEmpty(str)) { + return str; + } + int index = str.lastIndexOf(separator); + return index == INDEX_NOT_FOUND || index == str.length() - 1 ? EMPTY_STRING : str.substring(index + 1); + } + /** * Tokenize the given String into a String array. * Trims tokens and omits empty tokens. @@ -1317,6 +1343,10 @@ public static String[] tokenize(String str, char... separators) { return tokenizeToList(str, separators).toArray(EMPTY_STRING_ARRAY); } + /** + * Splits a string into a list of tokens using specified separators, trimming whitespace + * and ignoring empty tokens. Uses comma as default separator if none provided. + */ public static List tokenizeToList(String str, char... separators) { if (isEmpty(str)) { return Collections.emptyList(); @@ -1362,4 +1392,59 @@ public static List tokenizeToList(String str, char... separators) { } return tokens; } + + /** + * Converts string to Boolean based on common boolean representations. + * Supports values like 'true'/'false', 'yes'/'no', 'on'/'off', '1'/'0', etc. + * Returns null if the input cannot be parsed. + */ + public static Boolean toBoolean(String value) { + if (isEmpty(value)) { + return null; + } + switch (value.length()) { + case 1: + char c = value.charAt(0); + if (c == '0' || c == 'n' || c == 'N') { + return Boolean.FALSE; + } + if (c == '1' || c == 'y' || c == 'Y') { + return Boolean.TRUE; + } + break; + case 2: + if ("on".equalsIgnoreCase(value)) { + return Boolean.TRUE; + } + if ("no".equalsIgnoreCase(value)) { + return Boolean.FALSE; + } + break; + case 3: + if ("yes".equalsIgnoreCase(value)) { + return Boolean.TRUE; + } + if ("off".equalsIgnoreCase(value)) { + return Boolean.TRUE; + } + break; + case 4: + if ("true".equalsIgnoreCase(value)) { + return Boolean.TRUE; + } + break; + case 5: + if ("false".equalsIgnoreCase(value)) { + return Boolean.FALSE; + } + break; + default: + } + return null; + } + + public static boolean toBoolean(String value, boolean defaultValue) { + Boolean result = toBoolean(value); + return result == null ? defaultValue : result; + } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java index 2c481f7ca19..35da43e059e 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java @@ -37,6 +37,7 @@ import org.apache.dubbo.config.support.Nested; import org.apache.dubbo.config.support.Parameter; import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModel; import org.apache.dubbo.rpc.model.ScopeModelUtil; @@ -49,6 +50,7 @@ import java.beans.Transient; import java.io.Serializable; import java.lang.annotation.Annotation; +import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -325,6 +327,23 @@ private static boolean isParametersGetter(Method method) { && method.getReturnType() == Map.class); } + private static boolean isPropertySetter(Method method) { + String name = method.getName(); + if (name.startsWith("set") + && name.length() > 3 + && Modifier.isPublic(method.getModifiers()) + && method.getParameterCount() == 1) { + Class paramType = method.getParameterTypes()[0]; + if (paramType.isArray()) { + Class componentType = paramType.getComponentType(); + return componentType.isPrimitive() || isSimpleType(componentType); + } else { + return paramType.isPrimitive() || isSimpleType(paramType); + } + } + return false; + } + private static boolean isParametersSetter(Method method) { return ("setParameters".equals(method.getName()) && Modifier.isPublic(method.getModifiers()) @@ -770,11 +789,19 @@ private void assignProperties( // even if old one (this) contains non-null value, do override boolean overrideAll = configMode == ConfigMode.OVERRIDE_ALL; + FrameworkModel frameworkModel = ScopeModelUtil.getFrameworkModel(getScopeModel()); + // loop methods, get override value and set the new value back to method List methods = MethodUtils.getMethods(obj.getClass(), method -> method.getDeclaringClass() != Object.class); for (Method method : methods) { - if (MethodUtils.isSetter(method)) { + // filter non attribute + Parameter parameter = method.getAnnotation(Parameter.class); + if (parameter != null && !parameter.attribute()) { + continue; + } + + if (isPropertySetter(method)) { String propertyName = extractPropertyName(method.getName()); // if config mode is OVERRIDE_IF_ABSENT and property has set, skip @@ -787,17 +814,55 @@ private void assignProperties( try { String value = StringUtils.trim(configuration.getString(kebabPropertyName)); + + Class paramType = method.getParameterTypes()[0]; + if (paramType.isArray()) { + if (isIgnoredAttribute(obj.getClass(), propertyName)) { + continue; + } + + Class itemType = paramType.getComponentType(); + List items = new ArrayList<>(); + if (StringUtils.hasText(value)) { + value = environment.resolvePlaceholders(value); + if (StringUtils.hasText(value)) { + for (String item : StringUtils.tokenize(value, ',')) { + items.add(ClassUtils.convertPrimitive(frameworkModel, itemType, item)); + } + } + } else { + for (int i = 0; ; i++) { + value = StringUtils.trim(configuration.getString(kebabPropertyName + '[' + i + ']')); + if (value == null) { + break; + } + if (StringUtils.hasText(value)) { + value = environment.resolvePlaceholders(value); + if (StringUtils.hasText(value)) { + items.add(ClassUtils.convertPrimitive(frameworkModel, itemType, value)); + } + } + } + } + int len = items.size(); + if (len > 0) { + Object array = Array.newInstance(itemType, len); + for (int i = 0; i < len; i++) { + Array.set(array, i, items.get(i)); + } + method.invoke(obj, array); + } + continue; + } + // isTypeMatch() is called to avoid duplicate and incorrect update, for example, we have two // 'setGeneric' methods in ReferenceConfig. if (StringUtils.hasText(value) - && ClassUtils.isTypeMatch(method.getParameterTypes()[0], value) + && ClassUtils.isTypeMatch(paramType, value) && !isIgnoredAttribute(obj.getClass(), propertyName)) { value = environment.resolvePlaceholders(value); if (StringUtils.hasText(value)) { - Object arg = ClassUtils.convertPrimitive( - ScopeModelUtil.getFrameworkModel(getScopeModel()), - method.getParameterTypes()[0], - value); + Object arg = ClassUtils.convertPrimitive(frameworkModel, paramType, value); if (arg != null) { method.invoke(obj, arg); } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java new file mode 100644 index 00000000000..a482f0937d3 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java @@ -0,0 +1,332 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.config.nested; + +import java.io.Serializable; +import java.util.Map; + +public class OpenAPIConfig implements Serializable { + + private static final long serialVersionUID = 6943417456345001947L; + + /** + * Whether to enable OpenAPI support + *

The default value is 'true'. + */ + private Boolean enabled; + + /** + * Whether to cache the OpenAPI document. + *

The default value is 'true'. + */ + private Boolean cache; + + /** + * The HTTP path where OpenAPI will be registered. + *

The default value is '/dubbo/openapi'. + */ + private String path; + + /** + * The title of the OpenAPI information. + */ + private String infoTitle; + + /** + * A brief description of the OpenAPI information. + */ + private String infoDescription; + + /** + * The version number of the OpenAPI information. + */ + private String infoVersion; + + /** + * The name of the contact. + */ + private String infoContactName; + + /** + * The url of the contact. + */ + private String infoContactUrl; + + /** + * The email address of the contact. + */ + private String infoContactEmail; + + /** + * A description of the external documentation. + */ + private String externalDocsDescription; + + /** + * The URL of the external documentation. + */ + private String externalDocsUrl; + + /** + * A list of servers. + */ + private String[] servers; + + /** + * The security scheme. + */ + private String securityScheme; + + /** + * The security. + */ + private String security; + + /** + * The strategy used to generate operation id and schema name. + */ + private String nameStrategy; + + /** + * The default media types that are consumed. + */ + private String[] defaultConsumesMediaTypes; + + /** + * The default media types that are produced. + */ + private String[] defaultProducesMediaTypes; + + /** + * The default HTTP methods are used. + */ + private String[] defaultHttpMethods; + + /** + * The default HTTP status codes are returned. + */ + private String[] defaultHttpStatusCodes; + + /** + * Whether to flatten the inherited fields from the parent class into the schema. + *

The default value is {@code false}. + */ + private Boolean schemaFlatten; + + /** + * Specifies the classes to be excluded from schema generation. + *

For example: + *

    + *
  • com.example.MyClass - Exclude the MyClass class.
  • + *
  • com.example. - Exclude all classes in the com.example package.
  • + *
  • !com.example.exclude. - Exclude all classes except those in the com.example.exclude package.
  • + *
+ * Note that the package name should end with a dot (.) or an exclamation mark (!) to indicate the exclusion scope. + *

Multiple classes or package names can be separated by commas, for + * example: com.example.MyClass,com.example.,!com.example.exclude + */ + private String[] schemaClassExcludes; + + /** + * The custom settings. + */ + private Map settings; + + public Boolean getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public Boolean getCache() { + return cache; + } + + public void setCache(Boolean cache) { + this.cache = cache; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public String getInfoTitle() { + return infoTitle; + } + + public void setInfoTitle(String infoTitle) { + this.infoTitle = infoTitle; + } + + public String getInfoDescription() { + return infoDescription; + } + + public void setInfoDescription(String infoDescription) { + this.infoDescription = infoDescription; + } + + public String getInfoVersion() { + return infoVersion; + } + + public void setInfoVersion(String infoVersion) { + this.infoVersion = infoVersion; + } + + public String getInfoContactName() { + return infoContactName; + } + + public void setInfoContactName(String infoContactName) { + this.infoContactName = infoContactName; + } + + public String getInfoContactUrl() { + return infoContactUrl; + } + + public void setInfoContactUrl(String infoContactUrl) { + this.infoContactUrl = infoContactUrl; + } + + public String getInfoContactEmail() { + return infoContactEmail; + } + + public void setInfoContactEmail(String infoContactEmail) { + this.infoContactEmail = infoContactEmail; + } + + public String getExternalDocsDescription() { + return externalDocsDescription; + } + + public void setExternalDocsDescription(String externalDocsDescription) { + this.externalDocsDescription = externalDocsDescription; + } + + public String getExternalDocsUrl() { + return externalDocsUrl; + } + + public void setExternalDocsUrl(String externalDocsUrl) { + this.externalDocsUrl = externalDocsUrl; + } + + public String[] getServers() { + return servers; + } + + public void setServers(String[] servers) { + this.servers = servers; + } + + public String getSecurityScheme() { + return securityScheme; + } + + public void setSecurityScheme(String securityScheme) { + this.securityScheme = securityScheme; + } + + public String getSecurity() { + return security; + } + + public void setSecurity(String security) { + this.security = security; + } + + public String getNameStrategy() { + return nameStrategy; + } + + public void setNameStrategy(String nameStrategy) { + this.nameStrategy = nameStrategy; + } + + public String[] getDefaultConsumesMediaTypes() { + return defaultConsumesMediaTypes; + } + + public void setDefaultConsumesMediaTypes(String[] defaultConsumesMediaTypes) { + this.defaultConsumesMediaTypes = defaultConsumesMediaTypes; + } + + public String[] getDefaultProducesMediaTypes() { + return defaultProducesMediaTypes; + } + + public void setDefaultProducesMediaTypes(String[] defaultProducesMediaTypes) { + this.defaultProducesMediaTypes = defaultProducesMediaTypes; + } + + public String[] getDefaultHttpMethods() { + return defaultHttpMethods; + } + + public void setDefaultHttpMethods(String[] defaultHttpMethods) { + this.defaultHttpMethods = defaultHttpMethods; + } + + public String[] getDefaultHttpStatusCodes() { + return defaultHttpStatusCodes; + } + + public void setDefaultHttpStatusCodes(String[] defaultHttpStatusCodes) { + this.defaultHttpStatusCodes = defaultHttpStatusCodes; + } + + public Boolean getSchemaFlatten() { + return schemaFlatten; + } + + public void setSchemaFlatten(Boolean schemaFlatten) { + this.schemaFlatten = schemaFlatten; + } + + public String[] getSchemaClassExcludes() { + return schemaClassExcludes; + } + + public void setSchemaClassExcludes(String[] schemaClassExcludes) { + this.schemaClassExcludes = schemaClassExcludes; + } + + public Map getSettings() { + return settings; + } + + public void setSettings(Map settings) { + this.settings = settings; + } + + public String getSetting(String key) { + return settings == null ? null : settings.get(key); + } + + public String getSetting(String key, String defaultValue) { + return settings == null ? defaultValue : settings.getOrDefault(key, defaultValue); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/RestConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/RestConfig.java index 4e8d6a54eff..7cc994413fc 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/RestConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/RestConfig.java @@ -20,6 +20,7 @@ import org.apache.dubbo.config.support.Parameter; import java.io.Serializable; +import java.util.Map; /** * Configuration for triple rest protocol. @@ -33,6 +34,18 @@ public class RestConfig implements Serializable { public static final boolean DEFAULT_CASE_SENSITIVE_MATCH = true; public static final String DEFAULT_FORMAT_PARAMETER_NAME = "format"; + /** + * Whether to enable rest support + *

The default value is 'true'. + */ + private Boolean enabled; + + /** + * Whether to enable the default mapping '/{interfaceName}/{methodName}'. + *

The default value is 'true'. + */ + private Boolean enableDefaultMapping; + /** * Whether path matching should be match paths with a trailing slash. * If enabled, a method mapped to "/users" also matches to "/users/". @@ -67,12 +80,44 @@ public class RestConfig implements Serializable { */ private String jsonFramework; + /** + * The disallowed content-types. + */ + private String[] disallowedContentTypes; + /** * The cors configuration. */ @Nested private CorsConfig cors; + /** + * The openapi configuration. + */ + @Nested + private OpenAPIConfig openapi; + + /** + * Multiple configurations for openapi. + */ + private Map openapis; + + public Boolean getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public Boolean getEnableDefaultMapping() { + return enableDefaultMapping; + } + + public void setEnableDefaultMapping(Boolean enableDefaultMapping) { + this.enableDefaultMapping = enableDefaultMapping; + } + public Boolean getTrailingSlashMatch() { return trailingSlashMatch; } @@ -133,6 +178,14 @@ public void setJsonFramework(String jsonFramework) { this.jsonFramework = jsonFramework; } + public String[] getDisallowedContentTypes() { + return disallowedContentTypes; + } + + public void setDisallowedContentTypes(String[] disallowedContentTypes) { + this.disallowedContentTypes = disallowedContentTypes; + } + public CorsConfig getCors() { return cors; } @@ -148,4 +201,24 @@ public CorsConfig getCorsOrDefault() { public void setCors(CorsConfig cors) { this.cors = cors; } + + @Parameter(excluded = true) + public OpenAPIConfig getOpenapi() { + return openapi; + } + + @Parameter(attribute = false) + public void setOpenapi(OpenAPIConfig openapi) { + this.openapi = openapi; + } + + @Parameter(excluded = true) + public Map getOpenapis() { + return openapis; + } + + @Parameter(attribute = false) + public void setOpenapis(Map openapis) { + this.openapis = openapis; + } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/ServletConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/ServletConfig.java index 6bcbe50b609..d87938c5507 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/ServletConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/ServletConfig.java @@ -28,6 +28,14 @@ public class ServletConfig implements Serializable { */ private Boolean enabled; + /** + * Maximum concurrent streams. + *

For HTTP/2 + *

Note that the default value for tomcat is 20. Highly recommended to change it to {@link Integer#MAX_VALUE} + *

If set to zero or a negative number, the actual value will be set to {@link Integer#MAX_VALUE}. + */ + private Integer maxConcurrentStreams; + /** * The URL patterns that the servlet filter will be registered for. *

The default value is '/*'. @@ -48,6 +56,14 @@ public void setEnabled(Boolean enabled) { this.enabled = enabled; } + public Integer getMaxConcurrentStreams() { + return maxConcurrentStreams; + } + + public void setMaxConcurrentStreams(Integer maxConcurrentStreams) { + this.maxConcurrentStreams = maxConcurrentStreams; + } + public String[] getFilterUrlPatterns() { return filterUrlPatterns; } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/TripleConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/TripleConfig.java index 0e81f6f334d..854cb2d0518 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/TripleConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/TripleConfig.java @@ -152,6 +152,9 @@ public class TripleConfig implements Serializable { @Nested private ServletConfig servlet; + @Nested + private WebSocketConfig websocket; + public Boolean getVerbose() { return verbose; } @@ -370,4 +373,12 @@ public ServletConfig getServlet() { public void setServlet(ServletConfig servlet) { this.servlet = servlet; } + + public WebSocketConfig getWebsocket() { + return websocket; + } + + public void setWebsocket(WebSocketConfig websocket) { + this.websocket = websocket; + } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/WebSocketConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/WebSocketConfig.java new file mode 100644 index 00000000000..e2600f775b6 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/WebSocketConfig.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.dubbo.config.nested; + +import java.io.Serializable; + +public class WebSocketConfig implements Serializable { + + private static final long serialVersionUID = -2504271061733141988L; + + /** + * Whether to enable websocket support, requests are transport through the websocket container + *

The default value is false. + */ + private Boolean enabled; + + /** + * The URL patterns that the websocket filter will be registered for. + *

The default value is '/*'. + */ + private String[] filterUrlPatterns; + + /** + * The order of the websocket filter. + *

The default value is -1000000. + */ + private Integer filterOrder; + + public Boolean getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public String[] getFilterUrlPatterns() { + return filterUrlPatterns; + } + + public void setFilterUrlPatterns(String[] filterUrlPatterns) { + this.filterUrlPatterns = filterUrlPatterns; + } + + public Integer getFilterOrder() { + return filterOrder; + } + + public void setFilterOrder(Integer filterOrder) { + this.filterOrder = filterOrder; + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModel.java b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModel.java index 9e9d494a402..61b857f7569 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModel.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModel.java @@ -38,6 +38,7 @@ import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_UNABLE_DESTROY_MODEL; +@SuppressWarnings({"unchecked", "rawtypes"}) public abstract class ScopeModel implements ExtensionAccessor { protected static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(ScopeModel.class); @@ -200,10 +201,18 @@ public ExtensionDirector getExtensionDirector() { return extensionDirector; } - public ScopeBeanFactory getBeanFactory() { + public final ScopeBeanFactory getBeanFactory() { return beanFactory; } + public final T getOrRegisterBean(Class type) { + return beanFactory.getOrRegisterBean(type); + } + + public final T getBean(Class type) { + return beanFactory.getBean(type); + } + public ScopeModel getParent() { return parent; } @@ -259,6 +268,7 @@ public Set getClassLoaders() { * @deprecated use modelEnvironment() instead */ @Deprecated + @SuppressWarnings("DeprecatedIsStillUsed") public final Environment getModelEnvironment() { try { return modelEnvironment(); diff --git a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModelInitializer.java b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModelInitializer.java index 26c70ee0e85..ffcd867cbef 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModelInitializer.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModelInitializer.java @@ -22,9 +22,9 @@ @SPI(scope = ExtensionScope.SELF) public interface ScopeModelInitializer { - void initializeFrameworkModel(FrameworkModel frameworkModel); + default void initializeFrameworkModel(FrameworkModel frameworkModel) {} - void initializeApplicationModel(ApplicationModel applicationModel); + default void initializeApplicationModel(ApplicationModel applicationModel) {} - void initializeModuleModel(ModuleModel moduleModel); + default void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.utils.ParameterNameReader b/dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.utils.ParameterNameReader new file mode 100644 index 00000000000..b6e7ff292a5 --- /dev/null +++ b/dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.utils.ParameterNameReader @@ -0,0 +1 @@ +javassist=org.apache.dubbo.common.utils.JavassistParameterNameReader diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/support/eager/TaskQueueTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/support/eager/TaskQueueTest.java index a61e59a2184..13575605831 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/support/eager/TaskQueueTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/threadpool/support/eager/TaskQueueTest.java @@ -20,6 +20,7 @@ import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -29,6 +30,16 @@ class TaskQueueTest { + private TaskQueue queue; + private EagerThreadPoolExecutor executor; + + @BeforeEach + void setup() { + queue = new TaskQueue(1); + executor = mock(EagerThreadPoolExecutor.class); + queue.setExecutor(executor); + } + @Test void testOffer1() throws Exception { Assertions.assertThrows(RejectedExecutionException.class, () -> { @@ -39,53 +50,38 @@ void testOffer1() throws Exception { @Test void testOffer2() throws Exception { - TaskQueue queue = new TaskQueue(1); - EagerThreadPoolExecutor executor = mock(EagerThreadPoolExecutor.class); Mockito.when(executor.getPoolSize()).thenReturn(2); Mockito.when(executor.getActiveCount()).thenReturn(1); - queue.setExecutor(executor); assertThat(queue.offer(mock(Runnable.class)), is(true)); } @Test void testOffer3() throws Exception { - TaskQueue queue = new TaskQueue(1); - EagerThreadPoolExecutor executor = mock(EagerThreadPoolExecutor.class); Mockito.when(executor.getPoolSize()).thenReturn(2); Mockito.when(executor.getActiveCount()).thenReturn(2); Mockito.when(executor.getMaximumPoolSize()).thenReturn(4); - queue.setExecutor(executor); assertThat(queue.offer(mock(Runnable.class)), is(false)); } @Test void testOffer4() throws Exception { - TaskQueue queue = new TaskQueue(1); - EagerThreadPoolExecutor executor = mock(EagerThreadPoolExecutor.class); Mockito.when(executor.getPoolSize()).thenReturn(4); Mockito.when(executor.getActiveCount()).thenReturn(4); Mockito.when(executor.getMaximumPoolSize()).thenReturn(4); - queue.setExecutor(executor); assertThat(queue.offer(mock(Runnable.class)), is(true)); } @Test void testRetryOffer1() throws Exception { Assertions.assertThrows(RejectedExecutionException.class, () -> { - TaskQueue queue = new TaskQueue(1); - EagerThreadPoolExecutor executor = mock(EagerThreadPoolExecutor.class); Mockito.when(executor.isShutdown()).thenReturn(true); - queue.setExecutor(executor); queue.retryOffer(mock(Runnable.class), 1000, TimeUnit.MILLISECONDS); }); } @Test void testRetryOffer2() throws Exception { - TaskQueue queue = new TaskQueue(1); - EagerThreadPoolExecutor executor = mock(EagerThreadPoolExecutor.class); Mockito.when(executor.isShutdown()).thenReturn(false); - queue.setExecutor(executor); assertThat(queue.retryOffer(mock(Runnable.class), 1000, TimeUnit.MILLISECONDS), is(true)); } } diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DubboAppenderTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DubboAppenderTest.java index 2607ff877cc..9e68dab2764 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DubboAppenderTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/DubboAppenderTest.java @@ -27,8 +27,6 @@ import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assumptions.assumeFalse; -import static org.junit.jupiter.api.Assumptions.assumeTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -42,6 +40,9 @@ public void setUp() throws Exception { when(event.getLevel()).thenReturn(Level.INFO); when(event.getThreadName()).thenReturn("thread-name"); when(event.getMessage()).thenReturn(new SimpleMessage("message")); + + DubboAppender.clear(); + DubboAppender.doStop(); } @AfterEach @@ -52,7 +53,7 @@ public void tearDown() throws Exception { @Test void testAvailable() { - assumeFalse(DubboAppender.available); + assertThat(DubboAppender.available, is(false)); DubboAppender.doStart(); assertThat(DubboAppender.available, is(true)); DubboAppender.doStop(); @@ -62,8 +63,9 @@ void testAvailable() { @Test void testAppend() { DubboAppender appender = new DubboAppender(); + assertThat(DubboAppender.logList, hasSize(0)); appender.append(event); - assumeTrue(DubboAppender.logList.isEmpty()); + assertThat(DubboAppender.logList, hasSize(0)); DubboAppender.doStart(); appender.append(event); assertThat(DubboAppender.logList, hasSize(1)); @@ -75,7 +77,7 @@ void testClear() { DubboAppender.doStart(); DubboAppender appender = new DubboAppender(); appender.append(event); - assumeTrue(1 == DubboAppender.logList.size()); + assertThat(DubboAppender.logList, hasSize(1)); DubboAppender.clear(); assertThat(DubboAppender.logList, hasSize(0)); } diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/JavassistParameterNameReaderTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/JavassistParameterNameReaderTest.java new file mode 100644 index 00000000000..1118fdc6d4f --- /dev/null +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/JavassistParameterNameReaderTest.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.dubbo.common.utils; + +import org.apache.dubbo.common.URL; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.emptyArray; +import static org.hamcrest.Matchers.equalTo; + +class JavassistParameterNameReaderTest { + + private final ParameterNameReader reader = new JavassistParameterNameReader(); + + @Test + void readFromConstructor() { + Class clazz = URL.class; + for (Constructor ctor : clazz.getConstructors()) { + String[] names = reader.readParameterNames(ctor); + // System.out.println(ctor + " -> " + Arrays.toString(names)); + if (names.length == 7) { + assertThat(names[0], equalTo("protocol")); + } + } + } + + @Test + void readFromMethod() { + Class clazz = URL.class; + for (Method method : clazz.getMethods()) { + String[] names = reader.readParameterNames(method); + // System.out.println(method + " -> " + Arrays.toString(names)); + switch (method.getName()) { + case "getAddress": + assertThat(names, emptyArray()); + break; + case "setAddress": + assertThat(names[0], equalTo("address")); + break; + case "buildKey": + assertThat(names[0], equalTo("path")); + break; + default: + } + } + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/LockUtilsTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/LockUtilsTest.java index 87c18249303..dd080377a51 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/LockUtilsTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/LockUtilsTest.java @@ -114,7 +114,7 @@ void testInterrupt() { thread.interrupt(); await().until(() -> thread.getState() == State.TERMINATED); - Assertions.assertFalse(locked.get()); + Assertions.assertTrue(locked.get()); reentrantLock.unlock(); } @@ -141,4 +141,24 @@ void testHoldLock() throws InterruptedException { Assertions.assertTrue(lockTime.get() - startTime > 1000); Assertions.assertTrue(lockTime.get() - startTime < 10000); } + + @RepeatedTest(5) + void testInterrupted() throws InterruptedException { + ReentrantLock reentrantLock = new ReentrantLock(); + reentrantLock.lock(); + + AtomicLong lockTime = new AtomicLong(0); + long startTime = System.currentTimeMillis(); + Thread thread = new Thread(() -> { + Thread.currentThread().interrupt(); + LockUtils.safeLock(reentrantLock, 10000, () -> { + lockTime.set(System.currentTimeMillis()); + }); + }); + thread.start(); + + await().until(() -> thread.getState() == State.TERMINATED); + Assertions.assertTrue(lockTime.get() >= startTime); + Assertions.assertTrue(lockTime.get() - startTime < 10000); + } } diff --git a/dubbo-config/dubbo-config-api/pom.xml b/dubbo-config/dubbo-config-api/pom.xml index 3a29c6c7579..1cb5cd76e84 100644 --- a/dubbo-config/dubbo-config-api/pom.xml +++ b/dubbo-config/dubbo-config-api/pom.xml @@ -237,7 +237,7 @@ org.testcontainers testcontainers - 1.20.1 + 1.20.4 test diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java index 363eccd8b5e..33c9a581ab7 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java @@ -395,7 +395,7 @@ protected void exported() { exported = true; List exportedURLs = this.getExportedUrls(); exportedURLs.forEach(url -> { - if (url.getParameters().containsKey(SERVICE_NAME_MAPPING_KEY)) { + if (url.getParameter(SERVICE_NAME_MAPPING_KEY, false)) { ServiceNameMapping serviceNameMapping = ServiceNameMapping.getDefaultExtension(getScopeModel()); ScheduledExecutorService scheduledExecutor = getScopeModel() .getBeanFactory() diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java index 6b17d2a45d4..1077a61b737 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java @@ -137,6 +137,7 @@ public static void beforeAll() { @BeforeEach public void setUp() throws Exception { DubboBootstrap.reset(); + FrameworkModel.destroyAll(); ApplicationModel.defaultModel().getApplicationConfigManager(); DubboBootstrap.getInstance(); } @@ -144,6 +145,7 @@ public void setUp() throws Exception { @AfterEach public void tearDown() throws IOException { DubboBootstrap.reset(); + FrameworkModel.destroyAll(); Mockito.framework().clearInlineMocks(); } diff --git a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-provider/src/main/java/org/apache/dubbo/demo/provider/DemoServiceImpl.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/SpringParameterNameReader.java similarity index 50% rename from dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-provider/src/main/java/org/apache/dubbo/demo/provider/DemoServiceImpl.java rename to dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/SpringParameterNameReader.java index 8b4f9446500..f0556576373 100644 --- a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-provider/src/main/java/org/apache/dubbo/demo/provider/DemoServiceImpl.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/SpringParameterNameReader.java @@ -14,31 +14,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.demo.provider; +package org.apache.dubbo.config.spring.util; -import org.apache.dubbo.config.annotation.DubboService; -import org.apache.dubbo.demo.DemoService; -import org.apache.dubbo.rpc.RpcContext; +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.common.utils.ParameterNameReader; -import java.util.concurrent.CompletableFuture; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.springframework.core.DefaultParameterNameDiscoverer; +import org.springframework.core.ParameterNameDiscoverer; -@DubboService -public class DemoServiceImpl implements DemoService { - private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class); +@Activate(onClass = "org.springframework.core.DefaultParameterNameDiscoverer") +public class SpringParameterNameReader implements ParameterNameReader { + + private final ParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer(); @Override - public String sayHello(String name) { - logger.info("Hello " + name + ", request from consumer: " - + RpcContext.getServiceContext().getRemoteAddress()); - return "Hello " + name + ", response from provider: " - + RpcContext.getServiceContext().getLocalAddress(); + public String[] readParameterNames(Method method) { + return discoverer.getParameterNames(method); } @Override - public CompletableFuture sayHelloAsync(String name) { - return null; + public String[] readParameterNames(Constructor ctor) { + return discoverer.getParameterNames(ctor); } } diff --git a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.utils.ParameterNameReader b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.utils.ParameterNameReader new file mode 100644 index 00000000000..ad2dd3afeda --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.utils.ParameterNameReader @@ -0,0 +1 @@ +spring=org.apache.dubbo.config.spring.util.SpringParameterNameReader diff --git a/dubbo-config/dubbo-config-spring6/pom.xml b/dubbo-config/dubbo-config-spring6/pom.xml index b02a938c005..520beba17a3 100644 --- a/dubbo-config/dubbo-config-spring6/pom.xml +++ b/dubbo-config/dubbo-config-spring6/pom.xml @@ -28,8 +28,6 @@ 17 17 - 6.1.13 - 3.0.9 @@ -48,22 +46,22 @@ org.springframework spring-beans - ${spring.version} + ${spring-6.version} org.springframework spring-core - ${spring.version} + ${spring-6.version} org.springframework spring-web - ${spring.version} + ${spring-6.version} org.springframework spring-context - ${spring.version} + ${spring-6.version} javax.servlet @@ -74,7 +72,7 @@ org.springframework.boot spring-boot-starter-test - ${spring-boot.version} + ${spring-boot-3.version} test diff --git a/dubbo-config/pom.xml b/dubbo-config/pom.xml index ecfb4322ec3..bc404270a6d 100644 --- a/dubbo-config/pom.xml +++ b/dubbo-config/pom.xml @@ -56,8 +56,6 @@ [17,) - dubbo-config-api - dubbo-config-spring dubbo-config-spring6 diff --git a/dubbo-configcenter/dubbo-configcenter-zookeeper/pom.xml b/dubbo-configcenter/dubbo-configcenter-zookeeper/pom.xml index c1deb8c3e5b..45e12bd4e72 100644 --- a/dubbo-configcenter/dubbo-configcenter-zookeeper/pom.xml +++ b/dubbo-configcenter/dubbo-configcenter-zookeeper/pom.xml @@ -40,13 +40,6 @@ ${project.parent.version} - - org.apache.dubbo - dubbo-test-common - ${project.parent.version} - test - - org.apache.curator curator-framework diff --git a/dubbo-configcenter/pom.xml b/dubbo-configcenter/pom.xml index 96a25b9d6e9..4792c9304dd 100644 --- a/dubbo-configcenter/pom.xml +++ b/dubbo-configcenter/pom.xml @@ -38,12 +38,4 @@ false - - - org.apache.dubbo - dubbo-test-check - ${project.parent.version} - test - - diff --git a/dubbo-demo/README.md b/dubbo-demo/README.md index 3220be4a64c..b406bab414c 100644 --- a/dubbo-demo/README.md +++ b/dubbo-demo/README.md @@ -1,29 +1,13 @@ # Dubbo Demo -This directory contains basic usages of Dubbo to help Dubbo developers for debugging and smoke test purpose. If you are looking for Dubbo samples for study purpose, you should look into [here](https://github.com/apache/dubbo-samples) where you will find comprehensive usages for how to use Dubbo in different scenarios with the different features. +This directory contains basic Dubbo usages to help Dubbo developers with debugging and smoke test purposes. Check [dubbo-samples](https://github.com/apache/dubbo-samples) repository for more examples that showcase Dubbo's rich features. -## How To Build +## Brief introduction -To build all demo applications from the source code, simply step into '*dubbo-demo*' directory and use maven to build: +1. **`dubbo-demo-api`** + This demo demonstrates the basic usage of Dubbo's RPC protocol, serving as a fundamental example. It showcases how to define and implement a simple RPC service using Dubbo, how to start a server that serves at a specified port and then a consumer that consumes the service. +2. **`dubbo-demo-springboot`** + This demo illustrates the integration of Dubbo with Spring Boot, showing how Dubbo services can be utilized and configured within a Spring Boot application. It demonstrates how to configure and manage Dubbo services seamlessly through Spring Boot, making it ideal for developers leveraging the popular Spring Boot framework. +3. **`dubbo-demo-springboot-idl`** + This demo focuses on showcasing how to use Dubbo with Spring Boot when IDL (Interface Definition Language) files such as Proto files are available. It illustrates how developers can work with Dubbo services defined through IDL, integrating them into a Spring Boot application. -```bash -mvn clean package -``` - -After build completes, a couple of fat jars are generated under '*target*' directory under each module directories, for example: '*dubbo-demo-api-provider-${project.version}.jar*' can be found under the directory '*dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/target*'. - -## How To Run - -Since the generated artifacts are fat jars backed by spring boot maven plugin, they can be executed directly with '*java -jar*', and since multicast is used for service registration, a necessary system property '**-Djava.net.preferIPv4Stack=true**' is required in order to registry and discover the demo service properly. - -Use '*dubbo-demo/dubbo-demo-api*' as an example, to start the provider '*dubbo-demo-api-provider*', execute the following command: - -```bash -java -Djava.net.preferIPv4Stack=true -jar dubbo-demo-api-provider-${project.version}.jar -``` - -To run the consumer '*dubbo-demo-api-consumer*', execute the following command: - -```bash -java -Djava.net.preferIPv4Stack=true -jar dubbo-demo-api-consumer-${project.version}.jar -``` diff --git a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-consumer/pom.xml b/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-consumer/pom.xml deleted file mode 100644 index 85b651833c1..00000000000 --- a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-consumer/pom.xml +++ /dev/null @@ -1,109 +0,0 @@ - - - - 4.0.0 - - org.apache.dubbo - dubbo-demo-annotation - ${revision} - ../pom.xml - - - dubbo-demo-annotation-consumer - - - true - - - - - org.apache.dubbo - dubbo-demo-interface - ${project.version} - - - org.apache.dubbo - dubbo-registry-multicast - ${project.version} - - - org.apache.dubbo - dubbo-registry-zookeeper - ${project.version} - - - org.apache.dubbo - dubbo-registry-nacos - ${project.version} - - - com.alibaba.nacos - nacos-client - - - org.apache.dubbo - dubbo-configcenter-zookeeper - ${project.version} - - - org.apache.dubbo - dubbo-configcenter-nacos - ${project.version} - - - org.apache.dubbo - dubbo-metadata-report-zookeeper - ${project.version} - - - org.apache.dubbo - dubbo-metadata-report-nacos - ${project.version} - - - org.apache.dubbo - dubbo-rpc-dubbo - ${project.version} - - - org.apache.dubbo - dubbo-config-spring - ${project.version} - - - org.apache.dubbo - dubbo-remoting-netty4 - ${project.version} - - - org.apache.dubbo - dubbo-serialization-hessian2 - ${project.version} - - - org.apache.dubbo - dubbo-serialization-fastjson2 - ${project.version} - - - org.apache.logging.log4j - log4j-slf4j-impl - - - - diff --git a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-consumer/src/main/java/org/apache/dubbo/demo/consumer/Application.java b/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-consumer/src/main/java/org/apache/dubbo/demo/consumer/Application.java deleted file mode 100644 index 8f6d2e9c7dc..00000000000 --- a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-consumer/src/main/java/org/apache/dubbo/demo/consumer/Application.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.dubbo.demo.consumer; - -import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; -import org.apache.dubbo.demo.DemoService; -import org.apache.dubbo.demo.consumer.comp.DemoServiceComponent; - -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.PropertySource; - -public class Application { - /** - * In order to make sure multicast registry works, need to specify '-Djava.net.preferIPv4Stack=true' before - * launch the application - */ - public static void main(String[] args) { - AnnotationConfigApplicationContext context = - new AnnotationConfigApplicationContext(ConsumerConfiguration.class); - context.start(); - DemoService service = context.getBean("demoServiceComponent", DemoServiceComponent.class); - String hello = service.sayHello("world"); - System.out.println("result :" + hello); - } - - @Configuration - @EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.consumer.comp") - @PropertySource("classpath:/spring/dubbo-consumer.properties") - @ComponentScan(value = {"org.apache.dubbo.demo.consumer.comp"}) - static class ConsumerConfiguration {} -} diff --git a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-consumer/src/main/resources/spring/dubbo-consumer.properties b/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-consumer/src/main/resources/spring/dubbo-consumer.properties deleted file mode 100644 index 151fc038a07..00000000000 --- a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-consumer/src/main/resources/spring/dubbo-consumer.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. -# - -dubbo.application.name=dubbo-demo-annotation-consumer -dubbo.registry.address=zookeeper://127.0.0.1:2181 -dubbo.protocol.port=-1 diff --git a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-provider/pom.xml b/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-provider/pom.xml deleted file mode 100644 index 720724073b0..00000000000 --- a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-provider/pom.xml +++ /dev/null @@ -1,111 +0,0 @@ - - - - 4.0.0 - - org.apache.dubbo - dubbo-demo-annotation - ${revision} - ../pom.xml - - - dubbo-demo-annotation-provider - - - true - - - - - org.apache.dubbo - dubbo-demo-interface - ${project.parent.version} - - - org.apache.dubbo - dubbo-registry-multicast - ${project.version} - - - org.apache.dubbo - dubbo-registry-nacos - ${project.version} - - - com.alibaba.nacos - nacos-client - - - org.apache.dubbo - dubbo-registry-zookeeper - ${project.version} - - - org.apache.dubbo - dubbo-configcenter-zookeeper - ${project.version} - - - org.apache.dubbo - dubbo-configcenter-nacos - ${project.version} - - - org.apache.dubbo - dubbo-metadata-report-zookeeper - ${project.version} - - - org.apache.dubbo - dubbo-metadata-report-nacos - ${project.version} - - - org.apache.dubbo - dubbo-rpc-dubbo - ${project.version} - - - org.apache.dubbo - dubbo-config-spring - ${project.version} - - - org.apache.dubbo - dubbo-remoting-netty4 - ${project.version} - - - org.apache.dubbo - dubbo-serialization-hessian2 - ${project.version} - - - org.apache.dubbo - dubbo-serialization-fastjson2 - ${project.version} - - - org.apache.logging.log4j - log4j-slf4j-impl - - - - diff --git a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-provider/src/main/java/org/apache/dubbo/demo/provider/Application.java b/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-provider/src/main/java/org/apache/dubbo/demo/provider/Application.java deleted file mode 100644 index 56fe623cc90..00000000000 --- a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-provider/src/main/java/org/apache/dubbo/demo/provider/Application.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.dubbo.demo.provider; - -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; - -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.PropertySource; - -public class Application { - public static void main(String[] args) throws Exception { - AnnotationConfigApplicationContext context = - new AnnotationConfigApplicationContext(ProviderConfiguration.class); - context.start(); - System.in.read(); - } - - @Configuration - @EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.provider") - @PropertySource("classpath:/spring/dubbo-provider.properties") - static class ProviderConfiguration { - @Bean - public RegistryConfig registryConfig() { - RegistryConfig registryConfig = new RegistryConfig(); - registryConfig.setAddress("zookeeper://127.0.0.1:2181"); - return registryConfig; - } - } -} diff --git a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-provider/src/main/resources/log4j2.xml b/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-provider/src/main/resources/log4j2.xml deleted file mode 100644 index 69e1321d220..00000000000 --- a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-provider/src/main/resources/log4j2.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - diff --git a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-provider/src/main/resources/spring/dubbo-provider.properties b/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-provider/src/main/resources/spring/dubbo-provider.properties deleted file mode 100644 index 4b4913e0251..00000000000 --- a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-provider/src/main/resources/spring/dubbo-provider.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. -# -# - -dubbo.application.name=dubbo-demo-annotation-provider -dubbo.protocol.name=dubbo -dubbo.protocol.port=-1 diff --git a/dubbo-demo/dubbo-demo-api/dubbo-demo-api-consumer/pom.xml b/dubbo-demo/dubbo-demo-api/dubbo-demo-api-consumer/pom.xml index ce9ef312488..b7a69efaba8 100644 --- a/dubbo-demo/dubbo-demo-api/dubbo-demo-api-consumer/pom.xml +++ b/dubbo-demo/dubbo-demo-api/dubbo-demo-api-consumer/pom.xml @@ -33,7 +33,7 @@ org.apache.dubbo - dubbo-demo-interface + dubbo-demo-api-interface ${project.parent.version} diff --git a/dubbo-demo/dubbo-demo-api/dubbo-demo-api-consumer/src/main/java/org/apache/dubbo/demo/consumer/Application.java b/dubbo-demo/dubbo-demo-api/dubbo-demo-api-consumer/src/main/java/org/apache/dubbo/demo/consumer/Application.java index 07cbefed293..05087147ba7 100644 --- a/dubbo-demo/dubbo-demo-api/dubbo-demo-api-consumer/src/main/java/org/apache/dubbo/demo/consumer/Application.java +++ b/dubbo-demo/dubbo-demo-api/dubbo-demo-api-consumer/src/main/java/org/apache/dubbo/demo/consumer/Application.java @@ -16,13 +16,13 @@ */ package org.apache.dubbo.demo.consumer; +import org.apache.dubbo.api.demo.DemoService; import org.apache.dubbo.common.constants.CommonConstants; import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.ProtocolConfig; import org.apache.dubbo.config.ReferenceConfig; import org.apache.dubbo.config.RegistryConfig; import org.apache.dubbo.config.bootstrap.DubboBootstrap; -import org.apache.dubbo.demo.DemoService; import org.apache.dubbo.rpc.service.GenericService; public class Application { @@ -42,7 +42,7 @@ private static void runWithBootstrap() { bootstrap .application(new ApplicationConfig("dubbo-demo-api-consumer")) .registry(new RegistryConfig(REGISTRY_URL)) - .protocol(new ProtocolConfig(CommonConstants.DUBBO, -1)) + .protocol(new ProtocolConfig(CommonConstants.TRIPLE, -1)) .reference(reference) .start(); diff --git a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-interface/pom.xml b/dubbo-demo/dubbo-demo-api/dubbo-demo-api-interface/pom.xml similarity index 88% rename from dubbo-demo/dubbo-demo-native/dubbo-demo-native-interface/pom.xml rename to dubbo-demo/dubbo-demo-api/dubbo-demo-api-interface/pom.xml index 2184cc8e123..f81b9113374 100644 --- a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-interface/pom.xml +++ b/dubbo-demo/dubbo-demo-api/dubbo-demo-api-interface/pom.xml @@ -16,18 +16,19 @@ limitations under the License. --> - 4.0.0 org.apache.dubbo - dubbo-demo-native + dubbo-demo-api ${revision} ../pom.xml - dubbo-demo-native-interface + dubbo-demo-api-interface + UTF-8 true + diff --git a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/DemoService.java b/dubbo-demo/dubbo-demo-api/dubbo-demo-api-interface/src/main/java/org/apache/dubbo/api/demo/DemoService.java similarity index 96% rename from dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/DemoService.java rename to dubbo-demo/dubbo-demo-api/dubbo-demo-api-interface/src/main/java/org/apache/dubbo/api/demo/DemoService.java index 26f1ac524aa..c69307f3a21 100644 --- a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/DemoService.java +++ b/dubbo-demo/dubbo-demo-api/dubbo-demo-api-interface/src/main/java/org/apache/dubbo/api/demo/DemoService.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.demo; +package org.apache.dubbo.api.demo; import java.util.concurrent.CompletableFuture; diff --git a/dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/pom.xml b/dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/pom.xml index c29e4ababfb..74e0ca63ac2 100644 --- a/dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/pom.xml +++ b/dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/pom.xml @@ -35,7 +35,7 @@ org.apache.dubbo - dubbo-demo-interface + dubbo-demo-api-interface ${project.parent.version} diff --git a/dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/src/main/java/org/apache/dubbo/demo/provider/Application.java b/dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/src/main/java/org/apache/dubbo/demo/provider/Application.java index d6f70a57a1a..e51dda0dfe1 100644 --- a/dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/src/main/java/org/apache/dubbo/demo/provider/Application.java +++ b/dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/src/main/java/org/apache/dubbo/demo/provider/Application.java @@ -16,13 +16,13 @@ */ package org.apache.dubbo.demo.provider; +import org.apache.dubbo.api.demo.DemoService; import org.apache.dubbo.common.constants.CommonConstants; import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.ProtocolConfig; import org.apache.dubbo.config.RegistryConfig; import org.apache.dubbo.config.ServiceConfig; import org.apache.dubbo.config.bootstrap.DubboBootstrap; -import org.apache.dubbo.demo.DemoService; public class Application { diff --git a/dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/src/main/java/org/apache/dubbo/demo/provider/DemoServiceImpl.java b/dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/src/main/java/org/apache/dubbo/demo/provider/DemoServiceImpl.java index e7760f53a73..1a5b896783b 100644 --- a/dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/src/main/java/org/apache/dubbo/demo/provider/DemoServiceImpl.java +++ b/dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/src/main/java/org/apache/dubbo/demo/provider/DemoServiceImpl.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.demo.provider; -import org.apache.dubbo.demo.DemoService; +import org.apache.dubbo.api.demo.DemoService; import org.apache.dubbo.rpc.RpcContext; import java.util.concurrent.CompletableFuture; diff --git a/dubbo-demo/dubbo-demo-api/pom.xml b/dubbo-demo/dubbo-demo-api/pom.xml index 33ed7504dbd..bc40453768f 100644 --- a/dubbo-demo/dubbo-demo-api/pom.xml +++ b/dubbo-demo/dubbo-demo-api/pom.xml @@ -19,9 +19,9 @@ 4.0.0 org.apache.dubbo - dubbo-demo + dubbo-parent ${revision} - ../pom.xml + ../../pom.xml dubbo-demo-api @@ -30,6 +30,7 @@ dubbo-demo-api-provider dubbo-demo-api-consumer + dubbo-demo-api-interface @@ -37,21 +38,4 @@ 2.7.18 - - - - org.springframework.boot - spring-boot-maven-plugin - ${spring-boot-maven-plugin.version} - - - - repackage - - - - - - - diff --git a/dubbo-demo/dubbo-demo-generic-call/pom.xml b/dubbo-demo/dubbo-demo-generic-call/pom.xml deleted file mode 100644 index 47d82bcc454..00000000000 --- a/dubbo-demo/dubbo-demo-generic-call/pom.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - - 4.0.0 - - org.apache.dubbo - dubbo-demo - ${revision} - ../pom.xml - - - dubbo-demo-generic-call - - - true - - - - - org.apache.dubbo - dubbo-config-api - ${project.version} - - - org.apache.dubbo - dubbo-registry-multicast - ${project.version} - - - org.apache.dubbo - dubbo-registry-zookeeper - ${project.version} - - - org.apache.dubbo - dubbo-registry-nacos - ${project.version} - - - com.alibaba.nacos - nacos-client - - - org.apache.dubbo - dubbo-configcenter-zookeeper - ${project.version} - - - org.apache.dubbo - dubbo-configcenter-nacos - ${project.version} - - - org.apache.dubbo - dubbo-metadata-report-zookeeper - ${project.version} - - - org.apache.dubbo - dubbo-metadata-report-nacos - ${project.version} - - - org.apache.dubbo - dubbo-rpc-dubbo - ${project.version} - - - org.apache.dubbo - dubbo-remoting-netty4 - ${project.version} - - - org.apache.dubbo - dubbo-serialization-hessian2 - ${project.version} - - - org.apache.dubbo - dubbo-serialization-fastjson2 - ${project.version} - - - org.apache.logging.log4j - log4j-slf4j-impl - - - diff --git a/dubbo-demo/dubbo-demo-generic-call/src/main/java/org/apache/dubbo/demo/consumer/GenericApplication.java b/dubbo-demo/dubbo-demo-generic-call/src/main/java/org/apache/dubbo/demo/consumer/GenericApplication.java deleted file mode 100644 index 9b8a2210cb4..00000000000 --- a/dubbo-demo/dubbo-demo-generic-call/src/main/java/org/apache/dubbo/demo/consumer/GenericApplication.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.dubbo.demo.consumer; - -import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.common.utils.JsonUtils; -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.MetadataReportConfig; -import org.apache.dubbo.config.ProtocolConfig; -import org.apache.dubbo.config.ReferenceConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.bootstrap.DubboBootstrap; -import org.apache.dubbo.rpc.service.GenericService; - -public class GenericApplication { - - public static void main(String[] args) { - runWithBootstrap(args); - } - - private static void runWithBootstrap(String[] args) { - ReferenceConfig reference = new ReferenceConfig<>(); - reference.setInterface("org.apache.dubbo.demo.DemoService"); - - String param = "dubbo generic invoke"; - - if (args.length > 0 && CommonConstants.GENERIC_SERIALIZATION_GSON.equals(args[0])) { - reference.setGeneric(CommonConstants.GENERIC_SERIALIZATION_GSON); - param = JsonUtils.toJson(param + " gson"); - } else { - reference.setGeneric("true"); - } - - ApplicationConfig applicationConfig = new ApplicationConfig("demo-consumer"); - - MetadataReportConfig metadataReportConfig = new MetadataReportConfig(); - metadataReportConfig.setAddress("zookeeper://127.0.0.1:2181"); - - DubboBootstrap bootstrap = DubboBootstrap.getInstance(); - bootstrap - .application(applicationConfig) - .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) - .protocol(new ProtocolConfig(CommonConstants.DUBBO, -1)) - .reference(reference) - .start(); - - // generic invoke - GenericService genericService = bootstrap.getCache().get(reference); - while (true) { - try { - Object genericInvokeResult = - genericService.$invoke("sayHello", new String[] {String.class.getName()}, new Object[] {param}); - System.out.println(genericInvokeResult); - Thread.sleep(1000); - } catch (Exception e) { - e.printStackTrace(); - } - } - } -} diff --git a/dubbo-demo/dubbo-demo-generic-call/src/main/resources/log4j2.xml b/dubbo-demo/dubbo-demo-generic-call/src/main/resources/log4j2.xml deleted file mode 100644 index 69e1321d220..00000000000 --- a/dubbo-demo/dubbo-demo-generic-call/src/main/resources/log4j2.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - diff --git a/dubbo-demo/dubbo-demo-interface/pom.xml b/dubbo-demo/dubbo-demo-interface/pom.xml deleted file mode 100644 index 0c06266cb1b..00000000000 --- a/dubbo-demo/dubbo-demo-interface/pom.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - 4.0.0 - - org.apache.dubbo - dubbo-demo - ${revision} - ../pom.xml - - dubbo-demo-interface - jar - ${project.artifactId} - The demo module of dubbo project - - - true - - - - - - javax.ws.rs - javax.ws.rs-api - - - - org.springframework - spring-context - test - - - - org.springframework - spring-web - - - - org.apache.logging.log4j - log4j-slf4j-impl - - - - io.swagger - swagger-jaxrs - - - javax.ws.rs - jsr311-api - - - - - diff --git a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/RestDemoService.java b/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/RestDemoService.java deleted file mode 100644 index 0405b739f23..00000000000 --- a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/RestDemoService.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.dubbo.demo; - -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.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; - -import po.TestPO; - -@Path("/demoService") -public interface RestDemoService { - @GET - @Path("/hello") - @Consumes(MediaType.TEXT_PLAIN) - @Produces(MediaType.TEXT_PLAIN) - Integer hello(@QueryParam("a") Integer a, @QueryParam("b") Integer b); - - @GET - @Path("/error") - String error(); - - @POST - @Path("/say") - @Consumes({MediaType.TEXT_PLAIN}) - String sayHello(String name); - - @GET - @Path("/getRemoteApplicationName") - String getRemoteApplicationName(); - - @POST - @Path("/testBody1") - @Consumes({MediaType.TEXT_PLAIN}) - Integer testBody(Integer b); - - @POST - @Path("/testBody2") - @Consumes({MediaType.TEXT_PLAIN}) - String testBody2(String b); - - @POST - @Path("/testBody3") - @Consumes({MediaType.TEXT_PLAIN}) - Boolean testBody2(Boolean b); - - @POST - @Path("/testBody4") - @Consumes({MediaType.TEXT_PLAIN}) - TestPO testBody2(TestPO b); - - @POST - @Path("/testBody5") - @Consumes({MediaType.APPLICATION_JSON}) - @Produces({MediaType.APPLICATION_JSON}) - TestPO testBody5(TestPO testPO); - - @POST - @Path("/testForm1") - @Consumes(MediaType.APPLICATION_FORM_URLENCODED) - @Produces(MediaType.TEXT_PLAIN) - String testForm1(@FormParam("name") String test); - - @POST - @Path("/testForm2") - @Consumes(MediaType.APPLICATION_FORM_URLENCODED) - @Produces(MediaType.APPLICATION_FORM_URLENCODED) - MultivaluedMap testForm2(MultivaluedMap map); -} diff --git a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/rest/api/HttpMethodService.java b/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/rest/api/HttpMethodService.java deleted file mode 100644 index db1a815d46d..00000000000 --- a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/rest/api/HttpMethodService.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.dubbo.demo.rest.api; - -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.HEAD; -import javax.ws.rs.OPTIONS; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.QueryParam; - -import io.swagger.jaxrs.PATCH; - -@Path("/demoService") -public interface HttpMethodService { - - @POST - @Path("/sayPost") - @Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN}) - String sayHelloPost(String hello); - - @DELETE - @Path("/sayDelete") - @Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN}) - String sayHelloDelete(@QueryParam("name") String hello); - - @HEAD - @Path("/sayHead") - @Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN}) - String sayHelloHead(@QueryParam("name") String hello); - - @GET - @Path("/sayGet") - @Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN}) - String sayHelloGet(@QueryParam("name") String hello); - - @PUT - @Path("/sayPut") - @Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN}) - String sayHelloPut(@QueryParam("name") String hello); - - @PATCH - @Path("/sayPatch") - @Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN}) - String sayHelloPatch(@QueryParam("name") String hello); - - @OPTIONS - @Path("/sayOptions") - @Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN}) - String sayHelloOptions(@QueryParam("name") String hello); -} diff --git a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/rest/api/HttpRequestAndResponseRPCContextService.java b/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/rest/api/HttpRequestAndResponseRPCContextService.java deleted file mode 100644 index 4e925b386d8..00000000000 --- a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/rest/api/HttpRequestAndResponseRPCContextService.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.dubbo.demo.rest.api; - -import javax.ws.rs.Consumes; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.QueryParam; - -import java.util.List; - -@Path("/demoService") -public interface HttpRequestAndResponseRPCContextService { - - @POST - @Path("/httpRequestParam") - @Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN}) - String httpRequestParam(@QueryParam("name") String hello); - - @POST - @Path("/httpRequestHeader") - @Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN}) - String httpRequestHeader(@HeaderParam("header") String hello); - - @POST - @Path("/httpResponseHeader") - @Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN}) - List httpResponseHeader(@HeaderParam("response") String hello); -} diff --git a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/rest/api/JaxRsRestDemoService.java b/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/rest/api/JaxRsRestDemoService.java deleted file mode 100644 index 9b61aa54521..00000000000 --- a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/rest/api/JaxRsRestDemoService.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.dubbo.demo.rest.api; - -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.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; - -import java.util.List; -import java.util.Map; - -import po.User; - -/** - * - * @Consumers & @Produces can be not used ,we will make sure the content-type of request by arg type - * but the Request method is forbidden disappear - * parameters which annotation are not present , it is from the body (jaxrs annotation is different from spring web from param(only request param can ignore annotation)) - * - * Every method only one param from body - * - * the path annotation must present in class & method - */ -@Path("/jaxrs/demo/service") -public interface JaxRsRestDemoService { - @GET - @Path("/hello") - Integer hello(@QueryParam("a") Integer a, @QueryParam("b") Integer b); - - @GET - @Path("/error") - String error(); - - @POST - @Path("/say") - String sayHello(String name); - - @POST - @Path("/testFormBody") - Long testFormBody(@FormParam("number") Long number); - - @POST - @Path("/testJavaBeanBody") - @Consumes({MediaType.APPLICATION_JSON}) - User testJavaBeanBody(User user); - - @GET - @Path("/primitive") - int primitiveInt(@QueryParam("a") int a, @QueryParam("b") int b); - - @GET - @Path("/primitiveLong") - long primitiveLong(@QueryParam("a") long a, @QueryParam("b") Long b); - - @GET - @Path("/primitiveByte") - long primitiveByte(@QueryParam("a") byte a, @QueryParam("b") Long b); - - @POST - @Path("/primitiveShort") - long primitiveShort(@QueryParam("a") short a, @QueryParam("b") Long b, int c); - - @GET - @Path("testMapParam") - @Produces({MediaType.TEXT_PLAIN}) - @Consumes({MediaType.TEXT_PLAIN}) - String testMapParam(@QueryParam("test") Map params); - - @GET - @Path("testMapHeader") - @Produces({MediaType.TEXT_PLAIN}) - @Consumes({MediaType.TEXT_PLAIN}) - String testMapHeader(@HeaderParam("test") Map headers); - - @POST - @Path("testMapForm") - @Produces({MediaType.APPLICATION_JSON}) - @Consumes({MediaType.APPLICATION_FORM_URLENCODED}) - List testMapForm(MultivaluedMap params); - - @POST - @Path("/header") - @Consumes({MediaType.TEXT_PLAIN}) - String header(@HeaderParam("header") String header); - - @POST - @Path("/headerInt") - @Consumes({MediaType.TEXT_PLAIN}) - int headerInt(@HeaderParam("header") int header); -} diff --git a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/rest/api/SpringRestDemoService.java b/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/rest/api/SpringRestDemoService.java deleted file mode 100644 index ef726b5e2d3..00000000000 --- a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/rest/api/SpringRestDemoService.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.dubbo.demo.rest.api; - -import java.util.List; -import java.util.Map; - -import org.springframework.http.MediaType; -import org.springframework.util.MultiValueMap; -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 po.User; - -@RequestMapping("/spring/demo/service") -public interface SpringRestDemoService { - - @RequestMapping(method = RequestMethod.GET, value = "/hello") - Integer hello(@RequestParam("a") Integer a, @RequestParam("b") Integer b); - - @RequestMapping(method = RequestMethod.GET, value = "/error") - String error(); - - @RequestMapping(method = RequestMethod.POST, value = "/say") - String sayHello(@RequestBody String name); - - @RequestMapping( - method = RequestMethod.POST, - value = "/testFormBody", - consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) - Long testFormBody(@RequestBody Long number); - - @RequestMapping( - method = RequestMethod.POST, - value = "/testJavaBeanBody", - consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) - User testJavaBeanBody(@RequestBody User user); - - @RequestMapping(method = RequestMethod.GET, value = "/primitive") - int primitiveInt(@RequestParam("a") int a, @RequestParam("b") int b); - - @RequestMapping(method = RequestMethod.GET, value = "/primitiveLong") - long primitiveLong(@RequestParam("a") long a, @RequestParam("b") Long b); - - @RequestMapping(method = RequestMethod.GET, value = "/primitiveByte") - long primitiveByte(@RequestParam("a") byte a, @RequestParam("b") Long b); - - @RequestMapping(method = RequestMethod.POST, value = "/primitiveShort") - long primitiveShort(@RequestParam("a") short a, @RequestParam("b") Long b, @RequestBody int c); - - @RequestMapping(method = RequestMethod.GET, value = "/testMapParam") - String testMapParam(@RequestParam Map params); - - @RequestMapping(method = RequestMethod.GET, value = "/testMapHeader") - String testMapHeader(@RequestHeader Map headers); - - @RequestMapping( - method = RequestMethod.POST, - value = "/testMapForm", - consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) - List testMapForm(MultiValueMap params); - - @RequestMapping(method = RequestMethod.GET, value = "/headerInt") - int headerInt(@RequestHeader("header") int header); -} diff --git a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/pom.xml b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/pom.xml deleted file mode 100644 index 7078f54b19d..00000000000 --- a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/pom.xml +++ /dev/null @@ -1,216 +0,0 @@ - - - - - 4.0.0 - - org.apache.dubbo - dubbo-demo-native - ${revision} - ../pom.xml - - - dubbo-demo-native-consumer - - - true - 5.1.0 - 3.8.4 - - - - - org.apache.dubbo - dubbo-demo-native-interface - ${project.version} - - - org.apache.dubbo - dubbo-config-api - ${project.version} - - - org.apache.dubbo - dubbo-registry-multicast - ${project.version} - - - org.apache.curator - curator-x-discovery - ${curator5_version} - - - org.apache.curator - curator-recipes - ${curator5_version} - - - org.apache.curator - curator-framework - ${curator5_version} - - - org.apache.zookeeper - zookeeper - ${zookeeper_version} - - - io.netty - netty-handler - - - io.netty - netty-transport-native-epoll - - - ch.qos.logback - logback-core - - - - - - org.apache.dubbo - dubbo-registry-zookeeper - ${project.version} - - - org.apache.curator - curator-x-discovery - - - org.apache.zookeeper - zookeeper - - - org.apache.curator - curator-recipes - - - org.apache.curator - curator-framework - - - - - org.apache.dubbo - dubbo-rpc-dubbo - ${project.version} - - - org.apache.dubbo - dubbo-remoting-netty4 - ${project.version} - - - org.apache.dubbo - dubbo-serialization-fastjson2 - ${project.version} - - - org.apache.dubbo - dubbo-serialization-hessian2 - ${project.version} - - - - org.apache.dubbo - dubbo-filter-cache - ${project.version} - - - org.apache.dubbo - dubbo-filter-validation - ${project.version} - - - - org.apache.dubbo - dubbo-native - ${project.version} - - - ch.qos.logback - logback-classic - - - - ch.qos.logback - logback-core - 1.5.8 - compile - - - - - - native - - native - - - - - org.apache.dubbo - dubbo-maven-plugin - ${project.version} - - org.apache.dubbo.demo.graalvm.consumer.Application - - - - - dubbo-process-aot - - process-sources - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.13.0 - - 1.8 - 1.8 - true - true - UTF-8 - - ${project.basedir}${file.separator}src${file.separator}main${file.separator}java - - - - - org.graalvm.buildtools - native-maven-plugin - 0.10.3 - - ${project.build.outputDirectory} - - true - - 22.3 - org.apache.dubbo.demo.graalvm.consumer.Application - - - - - - - diff --git a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/src/main/java/org/apache/dubbo/demo/graalvm/consumer/Application.java b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/src/main/java/org/apache/dubbo/demo/graalvm/consumer/Application.java deleted file mode 100644 index 1c9ebb64e5e..00000000000 --- a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/src/main/java/org/apache/dubbo/demo/graalvm/consumer/Application.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.dubbo.demo.graalvm.consumer; - -import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.common.constants.CommonConstants.DubboProperty; -import org.apache.dubbo.common.utils.SystemPropertyConfigUtils; -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.ProtocolConfig; -import org.apache.dubbo.config.ReferenceConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.bootstrap.DubboBootstrap; -import org.apache.dubbo.graalvm.demo.DemoService; - -import java.util.HashMap; -import java.util.Map; - -public class Application { - - private static final String REGISTRY_URL = "zookeeper://127.0.0.1:2181"; - - public static void main(String[] args) { - SystemPropertyConfigUtils.setSystemProperty(DubboProperty.DUBBO_APPLICATION_LOGGER, "logback"); - System.setProperty("native", "true"); - SystemPropertyConfigUtils.setSystemProperty(DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME, "fastjson2"); - runWithBootstrap(); - } - - private static void runWithBootstrap() { - DubboBootstrap bootstrap = DubboBootstrap.getInstance(); - - ApplicationConfig applicationConfig = new ApplicationConfig("dubbo-demo-api-consumer"); - applicationConfig.setQosEnable(false); - applicationConfig.setCompiler("jdk"); - Map m = new HashMap<>(1); - m.put("proxy", "jdk"); - applicationConfig.setParameters(m); - - ReferenceConfig reference = new ReferenceConfig<>(); - reference.setInterface(DemoService.class); - reference.setGeneric("false"); - - ProtocolConfig protocolConfig = new ProtocolConfig(CommonConstants.DUBBO, -1); - protocolConfig.setSerialization("hessian2"); - bootstrap - .application(applicationConfig) - .registry(new RegistryConfig(REGISTRY_URL)) - .protocol(protocolConfig) - .reference(reference) - .start(); - - DemoService demoService = bootstrap.getCache().get(reference); - String message = demoService.sayHello("Native"); - System.out.println(message); - } -} diff --git a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/src/main/resources/META-INF/native-image/proxy-config.json b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/src/main/resources/META-INF/native-image/proxy-config.json deleted file mode 100644 index cb73756e52c..00000000000 --- a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/src/main/resources/META-INF/native-image/proxy-config.json +++ /dev/null @@ -1,7 +0,0 @@ -[ - [ - "org.apache.dubbo.graalvm.demo.DemoService", - "org.apache.dubbo.rpc.service.EchoService", - "org.apache.dubbo.rpc.service.Destroyable" - ] -] diff --git a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/src/main/resources/META-INF/native-image/reflect-config.json b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/src/main/resources/META-INF/native-image/reflect-config.json deleted file mode 100644 index eee360499b5..00000000000 --- a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/src/main/resources/META-INF/native-image/reflect-config.json +++ /dev/null @@ -1,17 +0,0 @@ -[ - { - "name": "org.apache.zookeeper.ClientCnxnSocketNIO", - "methods": [ - { - "name": "", - "parameterTypes": [ - "org.apache.zookeeper.client.ZKClientConfig" - ] - }, - { - "name": "", - "parameterTypes": [] - } - ] - } -] diff --git a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/src/main/resources/dubbo.properties b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/src/main/resources/dubbo.properties deleted file mode 100644 index 54015d0adf9..00000000000 --- a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/src/main/resources/dubbo.properties +++ /dev/null @@ -1 +0,0 @@ -native=true diff --git a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/src/main/resources/log4j2.xml b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/src/main/resources/log4j2.xml deleted file mode 100644 index 69e1321d220..00000000000 --- a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/src/main/resources/log4j2.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - diff --git a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/pom.xml b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/pom.xml deleted file mode 100644 index ecb5e538522..00000000000 --- a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/pom.xml +++ /dev/null @@ -1,216 +0,0 @@ - - - - - 4.0.0 - - org.apache.dubbo - dubbo-demo-native - ${revision} - ../pom.xml - - - dubbo-demo-native-provider - - - true - 5.1.0 - 3.8.4 - - - - - org.apache.dubbo - dubbo-demo-native-interface - ${project.version} - - - org.apache.dubbo - dubbo-config-api - ${project.version} - - - org.apache.dubbo - dubbo-registry-multicast - ${project.version} - - - org.apache.curator - curator-x-discovery - ${curator5_version} - - - org.apache.curator - curator-recipes - ${curator5_version} - - - org.apache.curator - curator-framework - ${curator5_version} - - - org.apache.zookeeper - zookeeper - ${zookeeper_version} - - - io.netty - netty-handler - - - io.netty - netty-transport-native-epoll - - - ch.qos.logback - logback-core - - - - - - org.apache.dubbo - dubbo-registry-zookeeper - ${project.version} - - - org.apache.curator - curator-x-discovery - - - org.apache.zookeeper - zookeeper - - - org.apache.curator - curator-recipes - - - org.apache.curator - curator-framework - - - - - org.apache.dubbo - dubbo-rpc-dubbo - ${project.version} - - - org.apache.dubbo - dubbo-remoting-netty4 - ${project.version} - - - org.apache.dubbo - dubbo-serialization-fastjson2 - ${project.version} - - - org.apache.dubbo - dubbo-serialization-hessian2 - ${project.version} - - - - org.apache.dubbo - dubbo-filter-cache - ${project.version} - - - org.apache.dubbo - dubbo-filter-validation - ${project.version} - - - - org.apache.dubbo - dubbo-native - ${project.version} - - - ch.qos.logback - logback-classic - - - - ch.qos.logback - logback-core - 1.5.8 - compile - - - - - - native - - native - - - - - org.apache.dubbo - dubbo-maven-plugin - ${project.version} - - org.apache.dubbo.demo.graalvm.provider.Application - - - - - dubbo-process-aot - - process-sources - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.13.0 - - 1.8 - 1.8 - true - true - UTF-8 - - ${project.basedir}${file.separator}src${file.separator}main${file.separator}java - - - - - org.graalvm.buildtools - native-maven-plugin - 0.10.3 - - ${project.build.outputDirectory} - - true - - 22.3 - org.apache.dubbo.demo.graalvm.provider.Application - - - - - - - diff --git a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/src/main/java/org/apache/dubbo/demo/graalvm/provider/Application.java b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/src/main/java/org/apache/dubbo/demo/graalvm/provider/Application.java deleted file mode 100644 index c0a4e9e4fd2..00000000000 --- a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/src/main/java/org/apache/dubbo/demo/graalvm/provider/Application.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.dubbo.demo.graalvm.provider; - -import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.common.constants.CommonConstants.DubboProperty; -import org.apache.dubbo.common.utils.SystemPropertyConfigUtils; -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.ProtocolConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.ServiceConfig; -import org.apache.dubbo.config.bootstrap.DubboBootstrap; -import org.apache.dubbo.graalvm.demo.DemoService; - -import java.util.HashMap; -import java.util.Map; - -public class Application { - - private static final String REGISTRY_URL = "zookeeper://127.0.0.1:2181"; - - public static void main(String[] args) throws Exception { - SystemPropertyConfigUtils.setSystemProperty(DubboProperty.DUBBO_APPLICATION_LOGGER, "logback"); - System.setProperty("native", "true"); - SystemPropertyConfigUtils.setSystemProperty(DubboProperty.DUBBO_PREFER_JSON_FRAMEWORK_NAME, "fastjson2"); - startWithBootstrap(); - System.in.read(); - } - - private static boolean isClassic(String[] args) { - return args.length > 0 && "classic".equalsIgnoreCase(args[0]); - } - - private static void startWithBootstrap() { - DubboBootstrap bootstrap = DubboBootstrap.getInstance(); - - ApplicationConfig applicationConfig = new ApplicationConfig("dubbo-demo-api-provider"); - applicationConfig.setQosEnable(false); - applicationConfig.setCompiler("jdk"); - Map m = new HashMap<>(1); - m.put("proxy", "jdk"); - applicationConfig.setParameters(m); - - ServiceConfig service = new ServiceConfig<>(); - service.setInterface(DemoService.class); - service.setRef(new DemoServiceImpl()); - - ProtocolConfig protocolConfig = new ProtocolConfig(CommonConstants.DUBBO, -1); - protocolConfig.setSerialization("hessian2"); - bootstrap - .application(applicationConfig) - .registry(new RegistryConfig(REGISTRY_URL)) - .protocol(protocolConfig) - .service(service) - .start() - .await(); - - System.out.println("dubbo service started"); - } -} diff --git a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/src/main/resources/META-INF/native-image/reflect-config.json b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/src/main/resources/META-INF/native-image/reflect-config.json deleted file mode 100644 index a0cb4a8a360..00000000000 --- a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/src/main/resources/META-INF/native-image/reflect-config.json +++ /dev/null @@ -1,25 +0,0 @@ -[ - { - "name": "org.apache.dubbo.graalvm.demo.DemoService", - "allPublicMethods": true - }, - { - "name": "org.apache.dubbo.demo.graalvm.provider.DemoServiceImpl", - "allDeclaredMethods": true - }, - { - "name": "org.apache.zookeeper.ClientCnxnSocketNIO", - "methods": [ - { - "name": "", - "parameterTypes": [ - "org.apache.zookeeper.client.ZKClientConfig" - ] - }, - { - "name": "", - "parameterTypes": [] - } - ] - } -] diff --git a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/src/main/resources/META-INF/native-image/resource-config.json b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/src/main/resources/META-INF/native-image/resource-config.json deleted file mode 100644 index 6bc4f4cc3b0..00000000000 --- a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/src/main/resources/META-INF/native-image/resource-config.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "resources": { - "includes": [ - { - "pattern": "\\Qdubbo.properties\\E" - }, - { - "pattern": "\\Qlog4j.properties\\E" - } - ] - }, - "bundles": [] -} diff --git a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/src/main/resources/dubbo.properties b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/src/main/resources/dubbo.properties deleted file mode 100644 index 54015d0adf9..00000000000 --- a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/src/main/resources/dubbo.properties +++ /dev/null @@ -1 +0,0 @@ -native=true diff --git a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/src/main/resources/log4j2.xml b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/src/main/resources/log4j2.xml deleted file mode 100644 index 69e1321d220..00000000000 --- a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/src/main/resources/log4j2.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - diff --git a/dubbo-demo/dubbo-demo-native/pom.xml b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/pom.xml similarity index 77% rename from dubbo-demo/dubbo-demo-native/pom.xml rename to dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/pom.xml index 4cf4a6654e8..5f574918aa3 100644 --- a/dubbo-demo/dubbo-demo-native/pom.xml +++ b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/pom.xml @@ -16,24 +16,27 @@ limitations under the License. --> - 4.0.0 org.apache.dubbo - dubbo-demo + dubbo-demo-spring-boot-idl ${revision} - ../pom.xml - dubbo-demo-native - pom - - dubbo-demo-native-consumer - dubbo-demo-native-provider - dubbo-demo-native-interface - + dubbo-demo-spring-boot-idl-consumer + UTF-8 true + + + + + org.apache.dubbo + dubbo-maven-plugin + + + + diff --git a/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/src/main/java/org/apache/dubbo/springboot/idl/demo/consumer/ConsumerApplication.java b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/src/main/java/org/apache/dubbo/springboot/idl/demo/consumer/ConsumerApplication.java new file mode 100644 index 00000000000..f18b1a85acc --- /dev/null +++ b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/src/main/java/org/apache/dubbo/springboot/idl/demo/consumer/ConsumerApplication.java @@ -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.dubbo.springboot.idl.demo.consumer; + +import org.apache.dubbo.config.annotation.DubboReference; +import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; +import org.apache.dubbo.demo.hello.GreeterService; +import org.apache.dubbo.demo.hello.HelloReply; +import org.apache.dubbo.demo.hello.HelloRequest; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.stereotype.Service; + +@SpringBootApplication +@Service +@EnableDubbo +public class ConsumerApplication { + + @DubboReference + private GreeterService demoService; + + public static void main(String[] args) { + + ConfigurableApplicationContext context = SpringApplication.run(ConsumerApplication.class, args); + ConsumerApplication application = context.getBean(ConsumerApplication.class); + HelloReply result = application.doSayHello("world"); + System.out.println("result: " + result.getMessage()); + } + + public HelloReply doSayHello(String name) { + return demoService.sayHello(HelloRequest.newBuilder().setName(name).build()); + } +} diff --git a/dubbo-demo/dubbo-demo-triple/src/main/proto/helloworld.proto b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/src/main/proto/helloworld.proto similarity index 79% rename from dubbo-demo/dubbo-demo-triple/src/main/proto/helloworld.proto rename to dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/src/main/proto/helloworld.proto index f23688817e9..8debdd28961 100644 --- a/dubbo-demo/dubbo-demo-triple/src/main/proto/helloworld.proto +++ b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/src/main/proto/helloworld.proto @@ -20,10 +20,16 @@ package helloworld; // The request message containing the user's name. message HelloRequest { - string name = 1; + string name = 1; } -// The response message containing the greetings +// The response message containing the greetings. message HelloReply { - string message = 1; + string message = 1; +} + +// Service definition. +service GreeterService { + // Sends a greeting. + rpc sayHello(HelloRequest) returns (HelloReply); } diff --git a/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/src/main/resources/application.yml b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/src/main/resources/application.yml new file mode 100644 index 00000000000..9cbc17d4d88 --- /dev/null +++ b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-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. + +spring: + application: + name: dubbo-springboot-idl-demo-consumer + +dubbo: + application: + name: ${spring.application.name} + protocol: + name: tri + port: -1 + registry: + id: zk-registry + address: zookeeper://127.0.0.1:2181 + config-center: + address: zookeeper://127.0.0.1:2181 + metadata-report: + address: zookeeper://127.0.0.1:2181 + + diff --git a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-consumer/src/main/resources/log4j2.xml b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/src/main/resources/log4j2.xml similarity index 87% rename from dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-consumer/src/main/resources/log4j2.xml rename to dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/src/main/resources/log4j2.xml index 69e1321d220..87c6dd5b190 100644 --- a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-consumer/src/main/resources/log4j2.xml +++ b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/src/main/resources/log4j2.xml @@ -18,7 +18,7 @@ - + diff --git a/dubbo-demo/dubbo-demo-annotation/pom.xml b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/pom.xml similarity index 66% rename from dubbo-demo/dubbo-demo-annotation/pom.xml rename to dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/pom.xml index 8e82740451a..68e1fabef6f 100644 --- a/dubbo-demo/dubbo-demo-annotation/pom.xml +++ b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/pom.xml @@ -19,36 +19,24 @@ 4.0.0 org.apache.dubbo - dubbo-demo + dubbo-demo-spring-boot-idl ${revision} - dubbo-demo-annotation - pom - - dubbo-demo-annotation-provider - dubbo-demo-annotation-consumer - + dubbo-demo-spring-boot-idl-provider + UTF-8 true - 2.7.18 - org.springframework.boot - spring-boot-maven-plugin - ${spring-boot-maven-plugin.version} - - - - repackage - - - + org.apache.dubbo + dubbo-maven-plugin + diff --git a/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/src/main/java/org/apache/dubbo/springboot/idl/demo/provider/GreeterServiceImpl.java b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/src/main/java/org/apache/dubbo/springboot/idl/demo/provider/GreeterServiceImpl.java new file mode 100644 index 00000000000..495af515c44 --- /dev/null +++ b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/src/main/java/org/apache/dubbo/springboot/idl/demo/provider/GreeterServiceImpl.java @@ -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.dubbo.springboot.idl.demo.provider; + +import org.apache.dubbo.config.annotation.DubboService; +import org.apache.dubbo.demo.hello.GreeterService; +import org.apache.dubbo.demo.hello.HelloReply; +import org.apache.dubbo.demo.hello.HelloRequest; + +import java.util.concurrent.CompletableFuture; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@DubboService +public class GreeterServiceImpl implements GreeterService { + + private static final Logger LOGGER = LoggerFactory.getLogger(GreeterServiceImpl.class); + + @Override + public HelloReply sayHello(HelloRequest request) { + LOGGER.info("Received sayHello request: {}", request.getName()); + return toReply("Hello " + request.getName()); + } + + @Override + public CompletableFuture sayHelloAsync(HelloRequest request) { + LOGGER.info("Received sayHelloAsync request: {}", request.getName()); + HelloReply.newBuilder().setMessage("Hello " + request.getName()); + return CompletableFuture.supplyAsync(() -> + HelloReply.newBuilder().setMessage("Hello " + request.getName()).build()); + } + + private static HelloReply toReply(String message) { + return HelloReply.newBuilder().setMessage(message).build(); + } +} diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-provider/src/main/java/org/apache/dubbo/demo/rest/api/SpringMvcRestProvider.java b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/src/main/java/org/apache/dubbo/springboot/idl/demo/provider/ProviderApplication.java similarity index 62% rename from dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-provider/src/main/java/org/apache/dubbo/demo/rest/api/SpringMvcRestProvider.java rename to dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/src/main/java/org/apache/dubbo/springboot/idl/demo/provider/ProviderApplication.java index 81bc1024812..488c22be385 100644 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-provider/src/main/java/org/apache/dubbo/demo/rest/api/SpringMvcRestProvider.java +++ b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/src/main/java/org/apache/dubbo/springboot/idl/demo/provider/ProviderApplication.java @@ -14,20 +14,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.demo.rest.api; +package org.apache.dubbo.springboot.idl.demo.provider; -import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; -public class SpringMvcRestProvider { +import java.util.concurrent.CountDownLatch; - public static void main(String[] args) throws Exception { - ClassPathXmlApplicationContext context = - new ClassPathXmlApplicationContext(new String[] {"spring/rest-provider.xml"}); - - context.refresh(); +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; - System.out.println("spring mvc rest provider started"); - - System.in.read(); +@SpringBootApplication +@EnableDubbo +public class ProviderApplication { + public static void main(String[] args) throws Exception { + SpringApplication.run(ProviderApplication.class, args); + System.out.println("dubbo service started"); + new CountDownLatch(1).await(); } } diff --git a/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/src/main/proto/helloworld.proto b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/src/main/proto/helloworld.proto new file mode 100644 index 00000000000..8debdd28961 --- /dev/null +++ b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/src/main/proto/helloworld.proto @@ -0,0 +1,35 @@ +// 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. +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.apache.dubbo.demo.hello"; +option java_outer_classname = "HelloWorldProto"; +option objc_class_prefix = "HLW"; + +package helloworld; + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings. +message HelloReply { + string message = 1; +} + +// Service definition. +service GreeterService { + // Sends a greeting. + rpc sayHello(HelloRequest) returns (HelloReply); +} diff --git a/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/src/main/resources/application.yml b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/src/main/resources/application.yml new file mode 100644 index 00000000000..88c5c29c489 --- /dev/null +++ b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/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. + +spring: + application: + name: dubbo-springboot-idl-demo-provider + +dubbo: + application: + name: ${spring.application.name} + protocol: + name: tri + port: -1 + registry: + id: zk-registry + address: zookeeper://127.0.0.1:2181 + config-center: + address: zookeeper://127.0.0.1:2181 + metadata-report: + address: zookeeper://127.0.0.1:2181 diff --git a/dubbo-demo/dubbo-demo-triple/src/main/resources/log4j2.xml b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/src/main/resources/log4j2.xml similarity index 100% rename from dubbo-demo/dubbo-demo-triple/src/main/resources/log4j2.xml rename to dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/src/main/resources/log4j2.xml diff --git a/dubbo-demo/dubbo-demo-triple/pom.xml b/dubbo-demo/dubbo-demo-spring-boot-idl/pom.xml similarity index 88% rename from dubbo-demo/dubbo-demo-triple/pom.xml rename to dubbo-demo/dubbo-demo-spring-boot-idl/pom.xml index 8fa55a99fbe..321057f5e4a 100644 --- a/dubbo-demo/dubbo-demo-triple/pom.xml +++ b/dubbo-demo/dubbo-demo-spring-boot-idl/pom.xml @@ -19,21 +19,35 @@ 4.0.0 org.apache.dubbo - dubbo-demo + dubbo-parent ${revision} - ../pom.xml + ../../pom.xml - dubbo-demo-triple + dubbo-demo-spring-boot-idl + pom + + dubbo-demo-spring-boot-idl-provider + dubbo-demo-spring-boot-idl-consumer + true - 1.8 - 1.8 + 2.7.18 3.13.0 + + org.apache.dubbo + dubbo-spring-boot-starter + ${revision} + + + org.springframework.boot + spring-boot-starter + ${spring-boot.version} + org.apache.dubbo dubbo-filter-cache @@ -157,18 +171,7 @@ - - org.apache.dubbo - dubbo-maven-plugin - ${project.version} - - - - compile - - - - + org.apache.maven.plugins diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/src/main/resources/application.yml b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/src/main/resources/application.yml index b1789be60fa..f154d3967bd 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/src/main/resources/application.yml +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/src/main/resources/application.yml @@ -22,7 +22,7 @@ dubbo: application: name: ${spring.application.name} protocol: - name: dubbo + name: tri port: -1 registry: id: zk-registry diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/pom.xml b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/pom.xml index afbf669558b..08eaf8e01a0 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/pom.xml +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/pom.xml @@ -32,6 +32,11 @@ dubbo-registry-zookeeper ${project.version} + + org.apache.dubbo + dubbo-qos + ${project.version} + org.apache.dubbo dubbo-rpc-triple @@ -52,11 +57,21 @@ dubbo-triple-servlet ${project.version} + + org.apache.dubbo + dubbo-rest-openapi + ${project.version} + org.apache.dubbo dubbo-serialization-hessian2 ${project.version} + + org.apache.dubbo + dubbo-remoting-netty4 + ${project.version} + org.apache.dubbo dubbo-config-spring @@ -82,6 +97,14 @@ org.springframework.boot spring-boot-starter-log4j2 + + + + com.github.therapi + therapi-runtime-javadoc-scribe + 0.15.0 + provided + @@ -90,6 +113,15 @@ org.springframework.boot spring-boot-maven-plugin + + org.apache.maven.plugins + maven-compiler-plugin + + + -parameters + + + diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml index f9628d83414..0ff09750d54 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml @@ -24,8 +24,12 @@ dubbo: qos-enable: false protocol: name: tri - port: ${server.port} + port: 8082 triple: + rest: + openapi: + enabled: true + cache: false servlet: enabled: true registry: diff --git a/dubbo-demo/dubbo-demo-spring-boot/pom.xml b/dubbo-demo/dubbo-demo-spring-boot/pom.xml index 77b5c8d6594..5edb4e6a3bf 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/pom.xml +++ b/dubbo-demo/dubbo-demo-spring-boot/pom.xml @@ -19,8 +19,9 @@ 4.0.0 org.apache.dubbo - dubbo-demo + dubbo-parent ${revision} + ../../pom.xml dubbo-demo-spring-boot @@ -33,10 +34,12 @@ + 1.8 + 1.8 true 2.7.18 2.7.18 - 1.13.3 + 1.14.1 diff --git a/dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/GreeterService.java b/dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/GreeterService.java deleted file mode 100644 index e9210d25923..00000000000 --- a/dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/GreeterService.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.dubbo.demo; - -import org.apache.dubbo.common.stream.StreamObserver; -import org.apache.dubbo.demo.hello.HelloReply; -import org.apache.dubbo.demo.hello.HelloRequest; - -import java.util.concurrent.CompletableFuture; - -public interface GreeterService { - - /** - * Sends a greeting - */ - HelloReply sayHello(HelloRequest request); - - /** - * Sends a greeting asynchronously - */ - CompletableFuture sayHelloAsync(String request); - - /** - * Sends a greeting with server streaming - */ - void sayHelloServerStream(HelloRequest request, StreamObserver responseObserver); - - /** - * Sends greetings with bi streaming - */ - StreamObserver sayHelloBiStream(StreamObserver responseObserver); -} diff --git a/dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/GreeterServiceImpl.java b/dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/GreeterServiceImpl.java deleted file mode 100644 index f5919b72a7a..00000000000 --- a/dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/GreeterServiceImpl.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.dubbo.demo; - -import org.apache.dubbo.common.stream.StreamObserver; -import org.apache.dubbo.demo.hello.HelloReply; -import org.apache.dubbo.demo.hello.HelloRequest; - -import java.util.concurrent.CompletableFuture; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class GreeterServiceImpl implements GreeterService { - - private static final Logger LOGGER = LoggerFactory.getLogger(GreeterServiceImpl.class); - - @Override - public HelloReply sayHello(HelloRequest request) { - LOGGER.info("Received sayHello request: {}", request.getName()); - return toReply("Hello " + request.getName()); - } - - @Override - public CompletableFuture sayHelloAsync(String name) { - LOGGER.info("Received sayHelloAsync request: {}", name); - return CompletableFuture.supplyAsync(() -> "Hello " + name); - } - - @Override - public void sayHelloServerStream(HelloRequest request, StreamObserver responseObserver) { - LOGGER.info("Received sayHelloServerStream request"); - for (int i = 1; i < 6; i++) { - LOGGER.info("sayHelloServerStream onNext: {} {} times", request.getName(), i); - responseObserver.onNext(toReply("Hello " + request.getName() + ' ' + i + " times")); - } - LOGGER.info("sayHelloServerStream onCompleted"); - responseObserver.onCompleted(); - } - - @Override - public StreamObserver sayHelloBiStream(StreamObserver responseObserver) { - LOGGER.info("Received sayHelloBiStream request"); - return new StreamObserver() { - @Override - public void onNext(HelloRequest request) { - LOGGER.info("sayHelloBiStream onNext: {}", request.getName()); - responseObserver.onNext(toReply("Hello " + request.getName())); - } - - @Override - public void onError(Throwable throwable) { - LOGGER.error("sayHelloBiStream onError", throwable); - } - - @Override - public void onCompleted() { - LOGGER.info("sayHelloBiStream onCompleted"); - } - }; - } - - private static HelloReply toReply(String message) { - return HelloReply.newBuilder().setMessage(message).build(); - } -} diff --git a/dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/consumer/ApiConsumer.java b/dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/consumer/ApiConsumer.java deleted file mode 100644 index 6a78b12f379..00000000000 --- a/dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/consumer/ApiConsumer.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.dubbo.demo.consumer; - -import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.common.stream.StreamObserver; -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.ProtocolConfig; -import org.apache.dubbo.config.ReferenceConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.bootstrap.DubboBootstrap; -import org.apache.dubbo.demo.GreeterService; -import org.apache.dubbo.demo.hello.HelloReply; -import org.apache.dubbo.demo.hello.HelloRequest; -import org.apache.dubbo.rpc.Constants; - -import java.util.Collections; -import java.util.concurrent.CompletableFuture; - -public class ApiConsumer { - - public static void main(String[] args) throws InterruptedException { - ReferenceConfig referenceConfig = new ReferenceConfig<>(); - referenceConfig.setInterface(GreeterService.class); - referenceConfig.setCheck(false); - referenceConfig.setProtocol(CommonConstants.TRIPLE); - referenceConfig.setLazy(true); - referenceConfig.setTimeout(100000); - if (args.length > 0 && Constants.HTTP3_KEY.equals(args[0])) { - referenceConfig.setParameters(Collections.singletonMap(Constants.HTTP3_KEY, "true")); - } - - DubboBootstrap bootstrap = DubboBootstrap.getInstance(); - bootstrap - .application(new ApplicationConfig("dubbo-demo-triple-api-consumer")) - .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) - .protocol(new ProtocolConfig(CommonConstants.TRIPLE, -1)) - .reference(referenceConfig) - .start(); - - GreeterService greeterService = referenceConfig.get(); - System.out.println("dubbo referenceConfig started"); - try { - System.out.println("Call sayHello"); - HelloReply reply = greeterService.sayHello(buildRequest("triple")); - System.out.println("sayHello reply: " + reply.getMessage()); - - System.out.println("Call sayHelloAsync"); - CompletableFuture sayHelloAsync = greeterService.sayHelloAsync("triple"); - sayHelloAsync.thenAccept(value -> System.out.println("sayHelloAsync reply: " + value)); - - StreamObserver responseObserver = new StreamObserver() { - @Override - public void onNext(HelloReply reply) { - System.out.println("sayHelloServerStream onNext: " + reply.getMessage()); - } - - @Override - public void onError(Throwable t) { - System.out.println("sayHelloServerStream onError: " + t.getMessage()); - } - - @Override - public void onCompleted() { - System.out.println("sayHelloServerStream onCompleted"); - } - }; - System.out.println("Call sayHelloServerStream"); - greeterService.sayHelloServerStream(buildRequest("triple"), responseObserver); - - StreamObserver biResponseObserver = new StreamObserver() { - @Override - public void onNext(HelloReply reply) { - System.out.println("biRequestObserver onNext: " + reply.getMessage()); - } - - @Override - public void onError(Throwable t) { - System.out.println("biResponseObserver onError: " + t.getMessage()); - } - - @Override - public void onCompleted() { - System.out.println("biResponseObserver onCompleted"); - } - }; - System.out.println("Call biRequestObserver"); - StreamObserver biRequestObserver = greeterService.sayHelloBiStream(biResponseObserver); - for (int i = 0; i < 5; i++) { - biRequestObserver.onNext(buildRequest("triple" + i)); - } - biRequestObserver.onCompleted(); - } catch (Throwable t) { - //noinspection CallToPrintStackTrace - t.printStackTrace(); - } - Thread.sleep(2000); - } - - private static HelloRequest buildRequest(String name) { - return HelloRequest.newBuilder().setName(name).build(); - } -} diff --git a/dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/consumer/ApiWrapperConsumer.java b/dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/consumer/ApiWrapperConsumer.java deleted file mode 100644 index 074dc9d2964..00000000000 --- a/dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/consumer/ApiWrapperConsumer.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.dubbo.demo.consumer; - -import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.ProtocolConfig; -import org.apache.dubbo.config.ReferenceConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.bootstrap.DubboBootstrap; -import org.apache.dubbo.demo.GreeterWrapperService; -import org.apache.dubbo.rpc.Constants; - -import java.io.IOException; -import java.util.Collections; - -public class ApiWrapperConsumer { - public static void main(String[] args) throws IOException { - ReferenceConfig referenceConfig = new ReferenceConfig<>(); - referenceConfig.setInterface(GreeterWrapperService.class); - referenceConfig.setCheck(false); - referenceConfig.setProtocol("tri"); - referenceConfig.setLazy(true); - if (args.length > 0 && Constants.HTTP3_KEY.equals(args[0])) { - referenceConfig.setParameters(Collections.singletonMap(Constants.HTTP3_KEY, "true")); - } - - DubboBootstrap bootstrap = DubboBootstrap.getInstance(); - bootstrap - .application(new ApplicationConfig("dubbo-demo-triple-api-wrapper-consumer")) - .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) - .protocol(new ProtocolConfig(CommonConstants.TRIPLE, -1)) - .reference(referenceConfig) - .start(); - - final GreeterWrapperService greeterWrapperService = referenceConfig.get(); - System.out.println("dubbo referenceConfig started"); - long st = System.currentTimeMillis(); - String reply = greeterWrapperService.sayHello("haha"); - // 4MB response - System.out.println("Reply length:" + reply.length() + " cost:" + (System.currentTimeMillis() - st)); - System.in.read(); - } -} diff --git a/dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/provider/ApiProvider.java b/dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/provider/ApiProvider.java deleted file mode 100644 index 91562677023..00000000000 --- a/dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/provider/ApiProvider.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.dubbo.demo.provider; - -import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.ProtocolConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.ServiceConfig; -import org.apache.dubbo.config.bootstrap.DubboBootstrap; -import org.apache.dubbo.demo.GreeterService; -import org.apache.dubbo.demo.GreeterServiceImpl; -import org.apache.dubbo.rpc.Constants; - -import java.util.Collections; - -public class ApiProvider { - - public static void main(String[] args) { - ServiceConfig serviceConfig = new ServiceConfig<>(); - serviceConfig.setInterface(GreeterService.class); - serviceConfig.setRef(new GreeterServiceImpl()); - if (args.length > 0 && Constants.HTTP3_KEY.equals(args[0])) { - serviceConfig.setParameters(Collections.singletonMap(Constants.HTTP3_KEY, "true")); - } - - DubboBootstrap bootstrap = DubboBootstrap.getInstance(); - bootstrap - .application(new ApplicationConfig("dubbo-demo-triple-api-provider")) - .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) - .protocol(new ProtocolConfig(CommonConstants.TRIPLE, -1)) - .service(serviceConfig) - .start() - .await(); - } -} diff --git a/dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/provider/ApiWrapperProvider.java b/dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/provider/ApiWrapperProvider.java deleted file mode 100644 index 27cdf25aff3..00000000000 --- a/dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/provider/ApiWrapperProvider.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.dubbo.demo.provider; - -import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.ProtocolConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.ServiceConfig; -import org.apache.dubbo.config.bootstrap.DubboBootstrap; -import org.apache.dubbo.demo.GreeterWrapperService; -import org.apache.dubbo.demo.GreeterWrapperServiceImpl; -import org.apache.dubbo.rpc.Constants; - -import java.io.IOException; -import java.util.Collections; - -public class ApiWrapperProvider { - public static void main(String[] args) throws IOException { - ServiceConfig serviceConfig = new ServiceConfig<>(); - serviceConfig.setInterface(GreeterWrapperService.class); - serviceConfig.setRef(new GreeterWrapperServiceImpl()); - if (args.length > 0 && Constants.HTTP3_KEY.equals(args[0])) { - serviceConfig.setParameters(Collections.singletonMap(Constants.HTTP3_KEY, "true")); - } - - DubboBootstrap bootstrap = DubboBootstrap.getInstance(); - bootstrap - .application(new ApplicationConfig("dubbo-demo-triple-api-wrapper-provider")) - .registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) - .protocol(new ProtocolConfig(CommonConstants.TRIPLE, -1)) - .service(serviceConfig) - .start() - .await(); - } -} diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-consumer/pom.xml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-consumer/pom.xml deleted file mode 100644 index 46cafa00479..00000000000 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-consumer/pom.xml +++ /dev/null @@ -1,146 +0,0 @@ - - - - 4.0.0 - - org.apache.dubbo - dubbo-demo-xml - ${revision} - ../pom.xml - - - dubbo-demo-spring-mvc-rest-consumer - - jar - ${project.artifactId} - Dubbo Spring MVC Rest Consumer Demo - - - true - - - - - org.springframework - spring-context - - - org.springframework - spring-web - - - - org.apache.dubbo - dubbo-registry-multicast - ${project.version} - - - org.apache.dubbo - dubbo-registry-zookeeper - ${project.version} - - - org.apache.dubbo - dubbo-registry-nacos - ${project.version} - - - com.alibaba.nacos - nacos-client - - - org.apache.dubbo - dubbo-configcenter-zookeeper - ${project.version} - - - org.apache.dubbo - dubbo-configcenter-nacos - ${project.version} - - - org.apache.dubbo - dubbo-metadata-report-zookeeper - ${project.version} - - - org.apache.dubbo - dubbo-metadata-report-nacos - ${project.version} - - - org.apache.dubbo - dubbo-rpc-dubbo - ${project.version} - - - org.apache.dubbo - dubbo-config-spring - ${project.version} - - - org.apache.dubbo - dubbo-remoting-netty4 - ${project.version} - - - org.apache.dubbo - dubbo-serialization-hessian2 - ${project.version} - - - org.apache.dubbo - dubbo-serialization-fastjson2 - ${project.version} - - - - org.springframework - spring-test - test - - - - org.apache.dubbo - dubbo-demo-interface - ${project.version} - - - org.apache.logging.log4j - log4j-slf4j-impl - - - - - - - javax.annotation - - [1.11,) - - - - javax.annotation - javax.annotation-api - 1.3.2 - - - - - - diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-consumer/src/main/java/org/apache/dubbo/demo/rest/api/SpringMvcRestConsumer.java b/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-consumer/src/main/java/org/apache/dubbo/demo/rest/api/SpringMvcRestConsumer.java deleted file mode 100644 index e64117cce0a..00000000000 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-consumer/src/main/java/org/apache/dubbo/demo/rest/api/SpringMvcRestConsumer.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.dubbo.demo.rest.api; - -import java.util.Arrays; - -import org.springframework.context.support.ClassPathXmlApplicationContext; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import po.User; - -public class SpringMvcRestConsumer { - - public static void main(String[] args) { - consumerService(); - } - - public static void consumerService() { - ClassPathXmlApplicationContext context = - new ClassPathXmlApplicationContext(new String[] {"spring/rest-consumer.xml"}); - context.start(); - System.out.println("spring mvc rest consumer start"); - springMvcRestDemoServiceTest(context); - System.out.println("spring mvc rest consumer test success"); - } - - private static void springMvcRestDemoServiceTest(ClassPathXmlApplicationContext context) { - SpringRestDemoService springRestDemoService = - context.getBean("springRestDemoService", SpringRestDemoService.class); - String hello = springRestDemoService.sayHello("hello"); - assertEquals("Hello, hello", hello); - Integer result = springRestDemoService.primitiveInt(1, 2); - Long resultLong = springRestDemoService.primitiveLong(1, 2l); - long resultByte = springRestDemoService.primitiveByte((byte) 1, 2l); - long resultShort = springRestDemoService.primitiveShort((short) 1, 2l, 1); - - assertEquals(result, 3); - assertEquals(resultShort, 3l); - assertEquals(resultLong, 3l); - assertEquals(resultByte, 3l); - - assertEquals(Long.valueOf(1l), springRestDemoService.testFormBody(1l)); - - MultiValueMap forms = new LinkedMultiValueMap<>(); - forms.put("form", Arrays.asList("F1")); - - assertEquals(Arrays.asList("F1"), springRestDemoService.testMapForm(forms)); - assertEquals(User.getInstance(), springRestDemoService.testJavaBeanBody(User.getInstance())); - } - - private static void assertEquals(Object returnStr, Object exception) { - boolean equal = returnStr != null && returnStr.equals(exception); - - if (equal) { - return; - } else { - throw new RuntimeException(); - } - } -} diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-consumer/src/main/java/org/apache/dubbo/demo/rest/api/config/DubboConfig.java b/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-consumer/src/main/java/org/apache/dubbo/demo/rest/api/config/DubboConfig.java deleted file mode 100644 index 0d9eab4ecb0..00000000000 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-consumer/src/main/java/org/apache/dubbo/demo/rest/api/config/DubboConfig.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.dubbo.demo.rest.api.config; - -import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan; - -@DubboComponentScan("org.apache.dubbo.demo.rest") -public class DubboConfig {} diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-consumer/src/main/resources/log4j2.xml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-consumer/src/main/resources/log4j2.xml deleted file mode 100644 index 69e1321d220..00000000000 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-consumer/src/main/resources/log4j2.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-consumer/src/main/resources/spring/rest-consumer.xml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-consumer/src/main/resources/spring/rest-consumer.xml deleted file mode 100644 index b0288791606..00000000000 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-consumer/src/main/resources/spring/rest-consumer.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-provider/pom.xml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-provider/pom.xml deleted file mode 100644 index aba2a7387a3..00000000000 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-provider/pom.xml +++ /dev/null @@ -1,146 +0,0 @@ - - - - 4.0.0 - - org.apache.dubbo - dubbo-demo-xml - ${revision} - ../pom.xml - - - dubbo-demo-spring-mvc-rest-provider - - jar - ${project.artifactId} - Dubbo Spring MVC Rest Provider Demo - - - true - - - - - org.springframework - spring-context - - - org.springframework - spring-web - - - - org.apache.dubbo - dubbo-registry-multicast - ${project.version} - - - org.apache.dubbo - dubbo-registry-zookeeper - ${project.version} - - - org.apache.dubbo - dubbo-registry-nacos - ${project.version} - - - com.alibaba.nacos - nacos-client - - - org.apache.dubbo - dubbo-configcenter-zookeeper - ${project.version} - - - org.apache.dubbo - dubbo-configcenter-nacos - ${project.version} - - - org.apache.dubbo - dubbo-metadata-report-zookeeper - ${project.version} - - - org.apache.dubbo - dubbo-metadata-report-nacos - ${project.version} - - - org.apache.dubbo - dubbo-rpc-dubbo - ${project.version} - - - org.apache.dubbo - dubbo-config-spring - ${project.version} - - - org.apache.dubbo - dubbo-remoting-netty4 - ${project.version} - - - org.apache.dubbo - dubbo-serialization-hessian2 - ${project.version} - - - org.apache.dubbo - dubbo-serialization-fastjson2 - ${project.version} - - - - org.springframework - spring-test - test - - - - org.apache.dubbo - dubbo-demo-interface - ${project.version} - - - org.apache.logging.log4j - log4j-slf4j-impl - - - - - - - javax.annotation - - [1.11,) - - - - javax.annotation - javax.annotation-api - 1.3.2 - - - - - - diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-provider/src/main/java/org/apache/dubbo/demo/rest/api/config/DubboConfig.java b/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-provider/src/main/java/org/apache/dubbo/demo/rest/api/config/DubboConfig.java deleted file mode 100644 index 0d9eab4ecb0..00000000000 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-provider/src/main/java/org/apache/dubbo/demo/rest/api/config/DubboConfig.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.dubbo.demo.rest.api.config; - -import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan; - -@DubboComponentScan("org.apache.dubbo.demo.rest") -public class DubboConfig {} diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-provider/src/main/java/org/apache/dubbo/demo/rest/api/impl/SpringRestDemoServiceImpl.java b/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-provider/src/main/java/org/apache/dubbo/demo/rest/api/impl/SpringRestDemoServiceImpl.java deleted file mode 100644 index 6cdaede32f0..00000000000 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-provider/src/main/java/org/apache/dubbo/demo/rest/api/impl/SpringRestDemoServiceImpl.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.dubbo.demo.rest.api.impl; - -import org.apache.dubbo.config.annotation.DubboService; -import org.apache.dubbo.demo.rest.api.SpringRestDemoService; - -import java.util.List; -import java.util.Map; - -import org.springframework.util.MultiValueMap; -import po.User; - -@DubboService(interfaceClass = SpringRestDemoService.class, protocol = "rest") -public class SpringRestDemoServiceImpl implements SpringRestDemoService { - - @Override - public String sayHello(String name) { - return "Hello, " + name; - } - - @Override - public Long testFormBody(Long number) { - return number; - } - - @Override - public User testJavaBeanBody(User user) { - return user; - } - - @Override - public int primitiveInt(int a, int b) { - return a + b; - } - - @Override - public long primitiveLong(long a, Long b) { - return a + b; - } - - @Override - public long primitiveByte(byte a, Long b) { - return a + b; - } - - @Override - public long primitiveShort(short a, Long b, int c) { - return a + b; - } - - @Override - public String testMapParam(Map params) { - return params.get("param"); - } - - @Override - public String testMapHeader(Map headers) { - return headers.get("header"); - } - - @Override - public List testMapForm(MultiValueMap params) { - return params.get("form"); - } - - @Override - public int headerInt(int header) { - return header; - } - - @Override - public Integer hello(Integer a, Integer b) { - return a + b; - } - - @Override - public String error() { - throw new RuntimeException("test error"); - } -} diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-provider/src/main/resources/log4j2.xml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-provider/src/main/resources/log4j2.xml deleted file mode 100644 index 69e1321d220..00000000000 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-provider/src/main/resources/log4j2.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-provider/src/main/resources/spring/rest-provider.xml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-provider/src/main/resources/spring/rest-provider.xml deleted file mode 100644 index 8c6be976f72..00000000000 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-spring-mvc-rest-provider/src/main/resources/spring/rest-provider.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/pom.xml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/pom.xml deleted file mode 100644 index cbd5e6d60c3..00000000000 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/pom.xml +++ /dev/null @@ -1,113 +0,0 @@ - - - - 4.0.0 - - org.apache.dubbo - dubbo-demo-xml - ${revision} - ../pom.xml - - dubbo-demo-xml-consumer - jar - ${project.artifactId} - The demo consumer module of dubbo project - - true - - - - org.apache.dubbo - dubbo-demo-interface - ${project.parent.version} - - - org.apache.dubbo - dubbo-registry-multicast - ${project.version} - - - org.apache.dubbo - dubbo-registry-nacos - ${project.version} - - - com.alibaba.nacos - nacos-client - - - org.apache.dubbo - dubbo-registry-zookeeper - ${project.version} - - - org.apache.dubbo - dubbo-configcenter-zookeeper - ${project.version} - - - org.apache.dubbo - dubbo-configcenter-nacos - ${project.version} - - - org.apache.dubbo - dubbo-metadata-report-zookeeper - ${project.version} - - - org.apache.dubbo - dubbo-metadata-report-nacos - ${project.version} - - - org.apache.dubbo - dubbo-config-spring - ${project.version} - - - org.apache.dubbo - dubbo-rpc-dubbo - ${project.version} - - - org.apache.dubbo - dubbo-remoting-netty4 - ${project.version} - - - org.apache.dubbo - dubbo-serialization-hessian2 - ${project.version} - - - org.apache.dubbo - dubbo-serialization-fastjson2 - ${project.version} - - - org.apache.dubbo - dubbo-rpc-triple - ${project.version} - - - org.apache.logging.log4j - log4j-slf4j-impl - - - diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/java/org/apache/dubbo/demo/consumer/Application.java b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/java/org/apache/dubbo/demo/consumer/Application.java deleted file mode 100644 index 2960b8d50e9..00000000000 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/java/org/apache/dubbo/demo/consumer/Application.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.dubbo.demo.consumer; - -import org.apache.dubbo.demo.DemoService; -import org.apache.dubbo.demo.GreetingService; -import org.apache.dubbo.demo.RestDemoService; -import org.apache.dubbo.demo.TripleService; - -import javax.ws.rs.core.MultivaluedHashMap; -import javax.ws.rs.core.MultivaluedMap; - -import java.util.Arrays; -import java.util.concurrent.CompletableFuture; - -import org.springframework.context.support.ClassPathXmlApplicationContext; -import po.TestPO; - -public class Application { - /** - * In order to make sure multicast registry works, need to specify '-Djava.net.preferIPv4Stack=true' before - * launch the application - */ - public static void main(String[] args) throws Exception { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-consumer.xml"); - context.start(); - DemoService demoService = context.getBean("demoService", DemoService.class); - GreetingService greetingService = context.getBean("greetingService", GreetingService.class); - RestDemoService restDemoService = context.getBean("restDemoService", RestDemoService.class); - TripleService tripleService = context.getBean("tripleService", TripleService.class); - - new Thread(() -> { - while (true) { - try { - String greetings = greetingService.hello(); - System.out.println(greetings + " from separated thread."); - } catch (Exception e) { - // e.printStackTrace(); - } - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - } - } - }) - .start(); - - new Thread(() -> { - while (true) { - try { - Object restResult = restDemoService.sayHello("rest"); - System.out.println(restResult + " from separated thread."); - restResult = restDemoService.testBody5(TestPO.getInstance()); - System.out.println(restResult + " from separated thread."); - - restResult = restDemoService.hello(1, 2); - System.out.println(restResult + " from separated thread."); - - String form1 = restDemoService.testForm1("form1"); - System.out.println(form1); - - MultivaluedHashMap multivaluedHashMap = new MultivaluedHashMap(); - multivaluedHashMap.put("1", Arrays.asList("1")); - multivaluedHashMap.put("2", Arrays.asList("2")); - MultivaluedMap form2 = restDemoService.testForm2(multivaluedHashMap); - System.out.println(form2); - } catch (Exception e) { - e.printStackTrace(); - } - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - } - } - }) - .start(); - - while (true) { - try { - CompletableFuture hello = demoService.sayHelloAsync("world"); - System.out.println("result: " + hello.get()); - - String greetings = greetingService.hello(); - System.out.println("result: " + greetings); - } catch (Exception e) { - // e.printStackTrace(); - } - - Thread.sleep(5000); - } - } -} diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/resources/dubbo-migration.yaml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/resources/dubbo-migration.yaml deleted file mode 100644 index 3f55a0bf360..00000000000 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/resources/dubbo-migration.yaml +++ /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. -# -# - -key: demo-consumer -step: APPLICATION_FIRST -threshold: 0.1 \ No newline at end of file diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/resources/dubbo.properties b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/resources/dubbo.properties deleted file mode 100644 index 8c3cb2559c7..00000000000 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/resources/dubbo.properties +++ /dev/null @@ -1 +0,0 @@ -dubbo.application.qos.port=33333 diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/resources/log4j2.xml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/resources/log4j2.xml deleted file mode 100644 index 69e1321d220..00000000000 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/resources/log4j2.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/resources/spring/dubbo-consumer.xml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/resources/spring/dubbo-consumer.xml deleted file mode 100644 index 0767baf39ab..00000000000 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/resources/spring/dubbo-consumer.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/java/org/apache/dubbo/demo/provider/Application.java b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/java/org/apache/dubbo/demo/provider/Application.java deleted file mode 100644 index d1ab5be7489..00000000000 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/java/org/apache/dubbo/demo/provider/Application.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.dubbo.demo.provider; - -import org.springframework.context.support.ClassPathXmlApplicationContext; - -public class Application { - public static void main(String[] args) throws Exception { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-provider.xml"); - context.start(); - System.in.read(); - } -} diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/java/org/apache/dubbo/demo/provider/DemoServiceImpl.java b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/java/org/apache/dubbo/demo/provider/DemoServiceImpl.java deleted file mode 100644 index 3467051454e..00000000000 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/java/org/apache/dubbo/demo/provider/DemoServiceImpl.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.dubbo.demo.provider; - -import org.apache.dubbo.demo.DemoService; -import org.apache.dubbo.rpc.RpcContext; - -import java.util.concurrent.CompletableFuture; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class DemoServiceImpl implements DemoService { - private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class); - - @Override - public String sayHello(String name) { - logger.info("Hello " + name + ", request from consumer: " - + RpcContext.getServiceContext().getRemoteAddress()); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return "Hello " + name + ", response from provider: " - + RpcContext.getServiceContext().getLocalAddress(); - } - - @Override - public CompletableFuture sayHelloAsync(String name) { - CompletableFuture cf = CompletableFuture.supplyAsync(() -> { - // try { - // Thread.sleep(1000); - // } catch (InterruptedException e) { - // e.printStackTrace(); - // } - return "async result"; - }); - return cf; - } -} diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/java/org/apache/dubbo/demo/provider/RestDemoServiceImpl.java b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/java/org/apache/dubbo/demo/provider/RestDemoServiceImpl.java deleted file mode 100644 index 37155fa436e..00000000000 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/java/org/apache/dubbo/demo/provider/RestDemoServiceImpl.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.dubbo.demo.provider; - -import org.apache.dubbo.demo.RestDemoService; -import org.apache.dubbo.rpc.RpcContext; - -import javax.ws.rs.core.MultivaluedMap; - -import java.util.Map; - -import po.TestPO; - -public class RestDemoServiceImpl implements RestDemoService { - private static Map context; - private boolean called; - - public String sayHello(String name) { - called = true; - return "Hello, " + name; - } - - public boolean isCalled() { - return called; - } - - @Override - public Integer hello(Integer a, Integer b) { - context = RpcContext.getServerAttachment().getObjectAttachments(); - return a + b; - } - - @Override - public String error() { - throw new RuntimeException(); - } - - public static Map getAttachments() { - return context; - } - - @Override - public String getRemoteApplicationName() { - return RpcContext.getServiceContext().getRemoteApplicationName(); - } - - @Override - public Integer testBody(Integer b) { - return b; - } - - @Override - public String testBody2(String b) { - return b; - } - - @Override - public Boolean testBody2(Boolean b) { - return b; - } - - @Override - public TestPO testBody2(TestPO b) { - return b; - } - - @Override - public TestPO testBody5(TestPO testPO) { - return testPO; - } - - public String testForm1(String test) { - return test; - } - - public MultivaluedMap testForm2(MultivaluedMap map) { - return map; - } -} diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/resources/dubbo.properties b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/resources/dubbo.properties deleted file mode 100644 index dde68cbdf04..00000000000 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/resources/dubbo.properties +++ /dev/null @@ -1,3 +0,0 @@ -dubbo.application.qos-enable=true -dubbo.application.qos-port=22222 -dubbo.application.qos-accept-foreign-ip=true diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/resources/log4j2.xml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/resources/log4j2.xml deleted file mode 100644 index 69e1321d220..00000000000 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/resources/log4j2.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/resources/spring/dubbo-provider.xml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/resources/spring/dubbo-provider.xml deleted file mode 100644 index ad402bc0683..00000000000 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/resources/spring/dubbo-provider.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/dubbo-demo/dubbo-demo-xml/pom.xml b/dubbo-demo/dubbo-demo-xml/pom.xml deleted file mode 100644 index 960f93e9e59..00000000000 --- a/dubbo-demo/dubbo-demo-xml/pom.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - 4.0.0 - - org.apache.dubbo - dubbo-demo - ${revision} - ../pom.xml - - - dubbo-demo-xml - pom - - - dubbo-demo-xml-provider - dubbo-demo-xml-consumer - dubbo-demo-spring-mvc-rest-consumer - dubbo-demo-spring-mvc-rest-provider - - - - true - 2.7.18 - - - - - - org.springframework.boot - spring-boot-maven-plugin - ${spring-boot-maven-plugin.version} - - - - repackage - - - - - - - - diff --git a/dubbo-dependencies-bom/pom.xml b/dubbo-dependencies-bom/pom.xml index 7b8f7c7dc46..844a31daca6 100644 --- a/dubbo-dependencies-bom/pom.xml +++ b/dubbo-dependencies-bom/pom.xml @@ -90,24 +90,26 @@ 5.3.39 - 5.8.14 + 2.7.18 + 5.8.16 3.30.2-GA - 1.15.1 + 1.15.10 3.2.10.Final - 4.1.113.Final + 4.1.115.Final 0.0.28.Final 4.5.14 4.4.16 - 1.2.83 - 2.0.52 + 1.2.83_noneautotype + 2.0.53 3.7.2 - 5.7.0 + 5.7.1 2.12.0 - 3.10.0 4.0.66 3.25.5 + 3.0.2 1.3.2 3.1.0 + 2.2.0 6.1.0 9.4.56.v20240826 3.1.0 @@ -120,14 +122,14 @@ 2.3 3.17.0 0.1.35 - 1.13.4 - 1.39.0 - 3.4.0 - 1.3.3 + 1.13.6 + 1.45.0 + 3.4.3 + 1.4.0 3.3 0.16.0 1.0.4 - 3.6.10 + 3.7.0 2.2.21 3.14.9 @@ -135,10 +137,10 @@ 3.15.6.Final 1.9.13 8.5.100 - 2.4.2 - 1.8.6 + 2.4.3 + 1.8.8 1.8.0 - 1.66.0 + 1.68.2 0.8.1 1.2.2 0.9.14 @@ -148,33 +150,31 @@ 1.2.17 1.2.13 - 2.24.0 - 2.16.1 - 1.16.0 - 4.0.21 + 2.24.2 + 2.18.0 + 1.17.1 + 4.0.24 - 5.9.3 - 4.13.2 - 4.2.0 + 5.11.3 + 1.11.3 + 4.2.2 2.2 2.2.2 - 1.4.3 4.11.0 2.3-groovy-4.0 2.2.7 1.2.0 - 1.20.1 + 1.20.4 4.0.3 1.6.14 1.1.10.7 1.70 - 5.4.3 2.0.6 2.11.0 - 2.17.2 + 2.18.2 6.1.26 2.0 1.6.0 @@ -183,11 +183,13 @@ check 1.0.0 2.38.0 - 3.1.9 4.0.2 2.4.0-b180830.0438 + + 1.15.1 + 0.16.0 - 3.3.1-SNAPSHOT + 3.3.3-SNAPSHOT @@ -214,6 +216,7 @@ pom import + io.micrometer micrometer-bom @@ -242,6 +245,50 @@ pom import + + io.prometheus + simpleclient_bom + ${prometheus-client.version} + pom + import + + + + org.springframework.boot + spring-boot-dependencies + ${spring_boot_version} + pom + import + + + io.micrometer + micrometer-core + + + + + org.springframework.boot + spring-boot-starter-logging + ${spring_boot_version} + + + ch.qos.logback + logback-classic + + + org.apache.logging.log4j + log4j-to-slf4j + + + org.slf4j + log4j-over-slf4j + + + org.slf4j + log4j-to-slf4j + + + io.netty netty-all @@ -350,11 +397,6 @@ - - redis.clients - jedis - ${jedis_version} - @@ -378,6 +420,11 @@ protobuf-java-util ${protobuf-java_version} + + com.google.code.findbugs + jsr305 + ${jsr305_version} + org.bouncycastle bcprov-jdk15on @@ -412,6 +459,18 @@ ${jakarta_servlet_version} provided + + jakarta.websocket + jakarta.websocket-api + ${jakarta_websocket_version} + provided + + + jakarta.websocket + jakarta.websocket-client-api + ${jakarta_websocket_version} + provided + com.squareup.okhttp3 okhttp @@ -662,19 +721,6 @@ ${swagger_version} - - - com.alipay.sofa - registry-client-all - ${sofa_registry_version} - - - com.alipay.sofa - registry-test - ${sofa_registry_version} - test - - org.junit.jupiter @@ -683,27 +729,33 @@ test - org.junit.jupiter - junit-jupiter-api - ${junit_jupiter_version} + org.junit.platform + junit-platform-engine + ${junit_platform_version} test - org.junit.jupiter - junit-jupiter-params - ${junit_jupiter_version} + org.junit.platform + junit-platform-commons + ${junit_platform_version} + test + + + org.junit.platform + junit-platform-launcher + ${junit_platform_version} test - org.junit.vintage - junit-vintage-engine + org.junit.jupiter + junit-jupiter-api ${junit_jupiter_version} test - junit - junit - ${junit_version} + org.junit.jupiter + junit-jupiter-params + ${junit_jupiter_version} test @@ -736,12 +788,6 @@ ${cglib_version} test - - com.github.codemonstur - embedded-redis - ${embedded_redis_version} - test - org.springframework spring-test @@ -930,11 +976,6 @@ rxjava ${rxjava.version} - - org.springframework.cloud - spring-cloud-openfeign-core - ${open_feign_version} - jakarta.xml.bind jakarta.xml.bind-api diff --git a/dubbo-dependencies/dubbo-dependencies-zookeeper-curator5/pom.xml b/dubbo-dependencies/dubbo-dependencies-zookeeper-curator5/pom.xml deleted file mode 100644 index b45047ba0e2..00000000000 --- a/dubbo-dependencies/dubbo-dependencies-zookeeper-curator5/pom.xml +++ /dev/null @@ -1,214 +0,0 @@ - - - - 4.0.0 - - org.apache - apache - 31 - - - - org.apache.dubbo - dubbo-dependencies-zookeeper-curator5 - ${revision} - pom - - - 1.6.0 - 1.7.36 - 5.1.0 - 3.8.4 - 2.43.0 - check - 1.0.0 - 2.38.0 - - 3.3.1-SNAPSHOT - - - - - org.apache.curator - curator-x-discovery - ${curator5_version} - - - org.apache.zookeeper - zookeeper - - - org.slf4j - slf4j-api - - - com.google.guava - listenablefuture - - - - - org.apache.zookeeper - zookeeper - ${zookeeper_version} - - - ch.qos.logback - logback-classic - - - ch.qos.logback - logback-core - - - org.apache.yetus - audience-annotations - - - io.netty - * - - - org.slf4j - slf4j-api - - - commons-io - commons-io - - - - - org.slf4j - slf4j-api - ${slf4j_version} - - - - - - - org.codehaus.mojo - flatten-maven-plugin - ${maven_flatten_version} - - true - oss - - - - flatten - - flatten - - process-resources - - - flatten.clean - - clean - - clean - - - - - - - - - release - - - - org.apache.maven.plugins - maven-gpg-plugin - - - - sign - - verify - - - - - - - - java11+ - - [11,) - - - - - - com.diffplug.spotless - spotless-maven-plugin - ${spotless-maven-plugin.version} - - - - ${palantirJavaFormat.version} - - - - dubbo-importorder.txt - - - checkstyle-header.txt - - - - - false - true - - - - true - - - - - com.alibaba - dubbo-shared-resources - ${dubbo-shared-resources.version} - - - - - - ${spotless.action} - - process-sources - - - - - - - - skip-spotless - - true - - - - diff --git a/dubbo-dependencies/pom.xml b/dubbo-dependencies/pom.xml deleted file mode 100644 index afc7ab7ab44..00000000000 --- a/dubbo-dependencies/pom.xml +++ /dev/null @@ -1,127 +0,0 @@ - - - - 4.0.0 - - org.apache.dubbo - dubbo-parent - ${revision} - ../pom.xml - - - dubbo-dependencies - pom - - dubbo-dependencies-zookeeper-curator5 - - - - 2.43.0 - check - 1.0.0 - 2.38.0 - - - - - - org.codehaus.mojo - flatten-maven-plugin - ${maven_flatten_version} - - true - bom - - - - flatten - - flatten - - process-resources - - - flatten.clean - - clean - - clean - - - - - - - - - java11+ - - [11,) - - - - - - com.diffplug.spotless - spotless-maven-plugin - ${spotless-maven-plugin.version} - - - - ${palantirJavaFormat.version} - - - - dubbo-importorder.txt - - - checkstyle-header.txt - - - - - false - true - - - - true - - - - - com.alibaba - dubbo-shared-resources - ${dubbo-shared-resources.version} - - - - - - ${spotless.action} - - process-sources - - - - - - - - - diff --git a/dubbo-distribution/dubbo-all-shaded/pom.xml b/dubbo-distribution/dubbo-all-shaded/pom.xml index eafb65386dd..a945581ddac 100644 --- a/dubbo-distribution/dubbo-all-shaded/pom.xml +++ b/dubbo-distribution/dubbo-all-shaded/pom.xml @@ -276,6 +276,13 @@ compile true + + org.apache.dubbo + dubbo-rest-openapi + ${project.version} + compile + true + org.apache.dubbo dubbo-triple-servlet @@ -283,6 +290,13 @@ compile true + + org.apache.dubbo + dubbo-triple-websocket + ${project.version} + compile + true + @@ -343,6 +357,13 @@ compile true + + org.apache.dubbo + dubbo-remoting-websocket + ${project.version} + compile + true + org.apache.dubbo dubbo-remoting-netty @@ -500,6 +521,7 @@ org.apache.dubbo:dubbo-remoting-api org.apache.dubbo:dubbo-remoting-http12 org.apache.dubbo:dubbo-remoting-http3 + org.apache.dubbo:dubbo-remoting-websocket org.apache.dubbo:dubbo-remoting-netty4 org.apache.dubbo:dubbo-remoting-netty org.apache.dubbo:dubbo-remoting-zookeeper-curator5 @@ -509,7 +531,9 @@ org.apache.dubbo:dubbo-rpc-triple org.apache.dubbo:dubbo-rest-jaxrs org.apache.dubbo:dubbo-rest-spring + org.apache.dubbo:dubbo-rest-openapi org.apache.dubbo:dubbo-triple-servlet + org.apache.dubbo:dubbo-triple-websocket org.apache.dubbo:dubbo-serialization-api org.apache.dubbo:dubbo-serialization-hessian2 org.apache.dubbo:dubbo-serialization-fastjson2 @@ -599,6 +623,9 @@ META-INF/dubbo/internal/org.apache.dubbo.common.threadpool.manager.ExecutorRepository + + META-INF/dubbo/internal/org.apache.dubbo.common.utils.ParameterNameReader + META-INF/dubbo/internal/org.apache.dubbo.common.url.component.param.DynamicParamSource @@ -742,6 +769,9 @@ META-INF/dubbo/internal/org.apache.dubbo.remoting.http3.Http3ServerTransportListenerFactory + + META-INF/dubbo/internal/org.apache.dubbo.remoting.websocket.WebSocketServerTransportListenerFactory + META-INF/dubbo/internal/org.apache.dubbo.remoting.telnet.TelnetHandler @@ -859,6 +889,9 @@ META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver + + META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension + META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.route.RequestHandlerMapping diff --git a/dubbo-distribution/dubbo-all/pom.xml b/dubbo-distribution/dubbo-all/pom.xml index 2f7828fe80a..8df563097d9 100644 --- a/dubbo-distribution/dubbo-all/pom.xml +++ b/dubbo-distribution/dubbo-all/pom.xml @@ -276,6 +276,13 @@ compile true + + org.apache.dubbo + dubbo-rest-openapi + ${project.version} + compile + true + org.apache.dubbo dubbo-triple-servlet @@ -283,6 +290,13 @@ compile true + + org.apache.dubbo + dubbo-triple-websocket + ${project.version} + compile + true + @@ -343,6 +357,13 @@ compile true + + org.apache.dubbo + dubbo-remoting-websocket + ${project.version} + compile + true + org.apache.dubbo dubbo-remoting-netty @@ -499,6 +520,7 @@ org.apache.dubbo:dubbo-remoting-api org.apache.dubbo:dubbo-remoting-http12 org.apache.dubbo:dubbo-remoting-http3 + org.apache.dubbo:dubbo-remoting-websocket org.apache.dubbo:dubbo-remoting-netty4 org.apache.dubbo:dubbo-remoting-netty org.apache.dubbo:dubbo-remoting-zookeeper-curator5 @@ -508,7 +530,9 @@ org.apache.dubbo:dubbo-rpc-triple org.apache.dubbo:dubbo-rest-jaxrs org.apache.dubbo:dubbo-rest-spring + org.apache.dubbo:dubbo-rest-openapi org.apache.dubbo:dubbo-triple-servlet + org.apache.dubbo:dubbo-triple-websocket org.apache.dubbo:dubbo-serialization-api org.apache.dubbo:dubbo-serialization-hessian2 org.apache.dubbo:dubbo-serialization-fastjson2 @@ -600,6 +624,9 @@ META-INF/dubbo/internal/org.apache.dubbo.common.url.component.param.DynamicParamSource + + META-INF/dubbo/internal/org.apache.dubbo.common.utils.ParameterNameReader + META-INF/dubbo/internal/org.apache.dubbo.config.ConfigInitializer @@ -740,6 +767,9 @@ META-INF/dubbo/internal/org.apache.dubbo.remoting.http3.Http3ServerTransportListenerFactory + + META-INF/dubbo/internal/org.apache.dubbo.remoting.websocket.WebSocketServerTransportListenerFactory + META-INF/dubbo/internal/org.apache.dubbo.remoting.telnet.TelnetHandler @@ -857,6 +887,9 @@ META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver + + META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension + META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.route.RequestHandlerMapping diff --git a/dubbo-distribution/dubbo-apache-release/pom.xml b/dubbo-distribution/dubbo-apache-release/pom.xml index 59fd7374580..edcdd03b5f1 100644 --- a/dubbo-distribution/dubbo-apache-release/pom.xml +++ b/dubbo-distribution/dubbo-apache-release/pom.xml @@ -19,9 +19,9 @@ 4.0.0 org.apache.dubbo - dubbo-distribution + dubbo-parent ${revision} - ../pom.xml + ../../pom.xml dubbo-apache-release pom diff --git a/dubbo-distribution/dubbo-bom/pom.xml b/dubbo-distribution/dubbo-bom/pom.xml index 4a0a8cc29d5..fd057752bb1 100644 --- a/dubbo-distribution/dubbo-bom/pom.xml +++ b/dubbo-distribution/dubbo-bom/pom.xml @@ -112,40 +112,12 @@ dubbo-configcenter-nacos ${project.version} - - - - org.apache.dubbo - dubbo-dependencies - ${project.version} - - - org.apache.dubbo - dubbo-dependencies-zookeeper - ${project.version} - pom - - - org.apache.dubbo - dubbo-dependencies-zookeeper-curator5 - ${project.version} - pom - - org.apache.dubbo dubbo-dependencies-bom ${project.version} - - - - org.apache.dubbo - dubbo-distribution - ${project.version} - pom - org.apache.dubbo dubbo @@ -287,11 +259,6 @@ - - org.apache.dubbo - dubbo-plugin - ${project.version} - org.apache.dubbo dubbo-auth @@ -334,11 +301,21 @@ dubbo-rest-spring ${project.version} + + org.apache.dubbo + dubbo-rest-openapi + ${project.version} + org.apache.dubbo dubbo-triple-servlet ${project.version} + + org.apache.dubbo + dubbo-triple-websocket + ${project.version} + @@ -395,6 +372,11 @@ dubbo-remoting-http3 ${project.version} + + org.apache.dubbo + dubbo-remoting-websocket + ${project.version} + org.apache.dubbo dubbo-remoting-netty @@ -475,6 +457,11 @@ dubbo-spring-boot-actuator ${project.version} + + org.apache.dubbo + dubbo-spring-boot-actuator-autoconfigure + ${project.version} + org.apache.dubbo dubbo-spring-boot-autoconfigure @@ -493,12 +480,12 @@ org.apache.dubbo - dubbo-spring-boot-actuator-compatible + dubbo-spring-boot-autoconfigure-compatible ${project.version} org.apache.dubbo - dubbo-spring-boot-autoconfigure-compatible + dubbo-spring-boot-actuator-autoconfigure-compatible ${project.version} @@ -508,7 +495,7 @@ org.apache.dubbo - dubbo-spring-boot-interceptor + dubbo-spring-boot ${project.version} @@ -517,17 +504,6 @@ ${project.version} pom - - org.apache.dubbo - dubbo-observability-spring-boot-starters - ${project.version} - pom - - - org.apache.dubbo - dubbo-observability-spring-boot-autoconfigure - ${project.version} - org.apache.dubbo dubbo-tracing-otel-zipkin-spring-boot-starter @@ -553,11 +529,6 @@ dubbo-nacos-spring-boot-starter ${project.version} - - org.apache.dubbo - dubbo-zookeeper-spring-boot-starter - ${project.version} - org.apache.dubbo dubbo-zookeeper-curator5-spring-boot-starter diff --git a/dubbo-distribution/dubbo-core-spi/pom.xml b/dubbo-distribution/dubbo-core-spi/pom.xml index 7592f4e99ad..0c6c789847f 100644 --- a/dubbo-distribution/dubbo-core-spi/pom.xml +++ b/dubbo-distribution/dubbo-core-spi/pom.xml @@ -223,6 +223,9 @@ META-INF/dubbo/internal/org.apache.dubbo.config.ConfigInitializer + + META-INF/dubbo/internal/org.apache.dubbo.common.utils.ParameterNameReader + META-INF/dubbo/internal/org.apache.dubbo.config.ConfigPostProcessor @@ -360,6 +363,9 @@ META-INF/dubbo/internal/org.apache.dubbo.remoting.http3.Http3ServerTransportListenerFactory + + META-INF/dubbo/internal/org.apache.dubbo.remoting.websocket.WebSocketServerTransportListenerFactory + META-INF/dubbo/internal/org.apache.dubbo.remoting.telnet.TelnetHandler @@ -477,6 +483,9 @@ META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver + + META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension + META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.route.RequestHandlerMapping diff --git a/dubbo-distribution/pom.xml b/dubbo-distribution/pom.xml deleted file mode 100644 index a61e230e9b8..00000000000 --- a/dubbo-distribution/pom.xml +++ /dev/null @@ -1,125 +0,0 @@ - - - - 4.0.0 - - org.apache.dubbo - dubbo-parent - ${revision} - ../pom.xml - - - dubbo-distribution - pom - - - 2.43.0 - check - 1.0.0 - 2.38.0 - - - - - release - - dubbo-all - dubbo-all-shaded - dubbo-apache-release - dubbo-bom - dubbo-core-spi - - - - dubbo-all - - [1.7,) - - - dubbo-all - dubbo-bom - - - - dubbo-core-spi - - dubbo-core-spi - - - - java11+ - - [11,) - - - - - - com.diffplug.spotless - spotless-maven-plugin - ${spotless-maven-plugin.version} - - - - ${palantirJavaFormat.version} - - - - dubbo-importorder.txt - - - checkstyle-header.txt - - - - - false - true - - - - true - - - - - com.alibaba - dubbo-shared-resources - ${dubbo-shared-resources.version} - - - - - - ${spotless.action} - - process-sources - - - - - - - - skip-spotless - - true - - - - diff --git a/dubbo-maven-plugin/pom.xml b/dubbo-maven-plugin/pom.xml index dbb042bd8a8..a25e21f04de 100644 --- a/dubbo-maven-plugin/pom.xml +++ b/dubbo-maven-plugin/pom.xml @@ -30,6 +30,7 @@ ${revision} 3.25.5 + @@ -56,7 +57,7 @@ org.apache.maven.plugin-tools maven-plugin-annotations - 3.15.0 + 3.15.1 provided @@ -75,7 +76,7 @@ commons-io commons-io - 2.16.1 + 2.18.0 @@ -111,7 +112,7 @@ org.apache.maven.plugins maven-plugin-plugin - 3.15.0 + 3.15.1 dubbo diff --git a/dubbo-metadata/dubbo-metadata-api/pom.xml b/dubbo-metadata/dubbo-metadata-api/pom.xml index 44e01099bd0..abeee99db63 100644 --- a/dubbo-metadata/dubbo-metadata-api/pom.xml +++ b/dubbo-metadata/dubbo-metadata-api/pom.xml @@ -62,6 +62,10 @@ ${project.parent.version} compile + + com.google.protobuf + protobuf-java + org.apache.dubbo @@ -81,4 +85,13 @@ ${project.parent.version} + + + + + + diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DubboMetadataServiceV2Triple.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DubboMetadataServiceV2Triple.java index 37cad3c89a9..cf77598c991 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DubboMetadataServiceV2Triple.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DubboMetadataServiceV2Triple.java @@ -27,6 +27,7 @@ import org.apache.dubbo.rpc.model.ServiceDescriptor; import org.apache.dubbo.rpc.model.StubMethodDescriptor; import org.apache.dubbo.rpc.model.StubServiceDescriptor; +import org.apache.dubbo.rpc.service.Destroyable; import org.apache.dubbo.rpc.stub.StubInvocationUtil; import org.apache.dubbo.rpc.stub.StubInvoker; import org.apache.dubbo.rpc.stub.StubMethodHandler; @@ -56,7 +57,7 @@ public final class DubboMetadataServiceV2Triple { StubSuppliers.addDescriptor(MetadataServiceV2.JAVA_SERVICE_NAME, serviceDescriptor); } - @SuppressWarnings("all") + @SuppressWarnings("unchecked") public static MetadataServiceV2 newStub(Invoker invoker) { return new MetadataServiceV2Stub((Invoker) invoker); } @@ -91,18 +92,55 @@ public static MetadataServiceV2 newStub(Invoker invoker) { MetadataRequest::parseFrom, MetadataInfoV2::parseFrom); + private static final StubMethodDescriptor getOpenAPIInfoMethod = new StubMethodDescriptor( + "GetOpenAPIInfo", + OpenAPIRequest.class, + OpenAPIInfo.class, + MethodDescriptor.RpcType.UNARY, + obj -> ((Message) obj).toByteArray(), + obj -> ((Message) obj).toByteArray(), + OpenAPIRequest::parseFrom, + OpenAPIInfo::parseFrom); + + private static final StubMethodDescriptor getOpenAPIInfoAsyncMethod = new StubMethodDescriptor( + "GetOpenAPIInfo", + OpenAPIRequest.class, + CompletableFuture.class, + MethodDescriptor.RpcType.UNARY, + obj -> ((Message) obj).toByteArray(), + obj -> ((Message) obj).toByteArray(), + OpenAPIRequest::parseFrom, + OpenAPIInfo::parseFrom); + + private static final StubMethodDescriptor getOpenAPIInfoProxyAsyncMethod = new StubMethodDescriptor( + "GetOpenAPIInfoAsync", + OpenAPIRequest.class, + OpenAPIInfo.class, + MethodDescriptor.RpcType.UNARY, + obj -> ((Message) obj).toByteArray(), + obj -> ((Message) obj).toByteArray(), + OpenAPIRequest::parseFrom, + OpenAPIInfo::parseFrom); + static { serviceDescriptor.addMethod(getMetadataInfoMethod); serviceDescriptor.addMethod(getMetadataInfoProxyAsyncMethod); + serviceDescriptor.addMethod(getOpenAPIInfoMethod); + serviceDescriptor.addMethod(getOpenAPIInfoProxyAsyncMethod); } - public static class MetadataServiceV2Stub implements MetadataServiceV2 { + public static class MetadataServiceV2Stub implements MetadataServiceV2, Destroyable { private final Invoker invoker; public MetadataServiceV2Stub(Invoker invoker) { this.invoker = invoker; } + @Override + public void $destroy() { + invoker.destroy(); + } + @Override public MetadataInfoV2 getMetadataInfo(MetadataRequest request) { return StubInvocationUtil.unaryCall(invoker, getMetadataInfoMethod, request); @@ -115,11 +153,23 @@ public CompletableFuture getMetadataInfoAsync(MetadataRequest re public void getMetadataInfo(MetadataRequest request, StreamObserver responseObserver) { StubInvocationUtil.unaryCall(invoker, getMetadataInfoMethod, request, responseObserver); } + + @Override + public OpenAPIInfo getOpenAPIInfo(OpenAPIRequest request) { + return StubInvocationUtil.unaryCall(invoker, getOpenAPIInfoMethod, request); + } + + public CompletableFuture getOpenAPIInfoAsync(OpenAPIRequest request) { + return StubInvocationUtil.unaryCall(invoker, getOpenAPIInfoAsyncMethod, request); + } + + public void getOpenAPIInfo(OpenAPIRequest request, StreamObserver responseObserver) { + StubInvocationUtil.unaryCall(invoker, getOpenAPIInfoMethod, request, responseObserver); + } } public abstract static class MetadataServiceV2ImplBase implements MetadataServiceV2, ServerService { - private BiConsumer> syncToAsync(java.util.function.Function syncFun) { return new BiConsumer>() { @Override @@ -140,10 +190,15 @@ public CompletableFuture getMetadataInfoAsync(MetadataRequest re return CompletableFuture.completedFuture(getMetadataInfo(request)); } - /** - * This server stream type unary method is only used for generated stub to support async unary method. - * It will not be called if you are NOT using Dubbo3 generated triple stub and DO NOT implement this method. - */ + @Override + public CompletableFuture getOpenAPIInfoAsync(OpenAPIRequest request) { + return CompletableFuture.completedFuture(getOpenAPIInfo(request)); + } + + // This server stream type unary method is only used for generated stub to support async unary method. + // It will not be called if you are NOT using Dubbo3 generated triple stub and DO NOT implement this + // method. + public void getMetadataInfo(MetadataRequest request, StreamObserver responseObserver) { getMetadataInfoAsync(request).whenComplete((r, t) -> { if (t != null) { @@ -155,19 +210,33 @@ public void getMetadataInfo(MetadataRequest request, StreamObserver responseObserver) { + getOpenAPIInfoAsync(request).whenComplete((r, t) -> { + if (t != null) { + responseObserver.onError(t); + } else { + responseObserver.onNext(r); + responseObserver.onCompleted(); + } + }); + } + @Override public final Invoker getInvoker(URL url) { PathResolver pathResolver = url.getOrDefaultFrameworkModel() .getExtensionLoader(PathResolver.class) .getDefaultExtension(); Map> handlers = new HashMap<>(); - pathResolver.addNativeStub("/" + SERVICE_NAME + "/GetMetadataInfo"); pathResolver.addNativeStub("/" + SERVICE_NAME + "/GetMetadataInfoAsync"); // for compatibility pathResolver.addNativeStub("/" + JAVA_SERVICE_NAME + "/GetMetadataInfo"); pathResolver.addNativeStub("/" + JAVA_SERVICE_NAME + "/GetMetadataInfoAsync"); - + pathResolver.addNativeStub("/" + SERVICE_NAME + "/GetOpenAPIInfo"); + pathResolver.addNativeStub("/" + SERVICE_NAME + "/GetOpenAPIInfoAsync"); + // for compatibility + pathResolver.addNativeStub("/" + JAVA_SERVICE_NAME + "/GetOpenAPIInfo"); + pathResolver.addNativeStub("/" + JAVA_SERVICE_NAME + "/GetOpenAPIInfoAsync"); BiConsumer> getMetadataInfoFunc = this::getMetadataInfo; handlers.put(getMetadataInfoMethod.getMethodName(), new UnaryStubMethodHandler<>(getMetadataInfoFunc)); BiConsumer> getMetadataInfoAsyncFunc = @@ -175,6 +244,13 @@ public final Invoker getInvoker(URL url) { handlers.put( getMetadataInfoProxyAsyncMethod.getMethodName(), new UnaryStubMethodHandler<>(getMetadataInfoAsyncFunc)); + BiConsumer> getOpenAPIInfoFunc = this::getOpenAPIInfo; + handlers.put(getOpenAPIInfoMethod.getMethodName(), new UnaryStubMethodHandler<>(getOpenAPIInfoFunc)); + BiConsumer> getOpenAPIInfoAsyncFunc = + syncToAsync(this::getOpenAPIInfo); + handlers.put( + getOpenAPIInfoProxyAsyncMethod.getMethodName(), + new UnaryStubMethodHandler<>(getOpenAPIInfoAsyncFunc)); return new StubInvoker<>(this, url, MetadataServiceV2.class, handlers); } @@ -184,6 +260,11 @@ public MetadataInfoV2 getMetadataInfo(MetadataRequest request) { throw unimplementedMethodException(getMetadataInfoMethod); } + @Override + public OpenAPIInfo getOpenAPIInfo(OpenAPIRequest request) { + throw unimplementedMethodException(getOpenAPIInfoMethod); + } + @Override public final ServiceDescriptor getServiceDescriptor() { return serviceDescriptor; diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfo.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfo.java index 0a2f8c698be..d7dccf8df1c 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfo.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfo.java @@ -294,7 +294,9 @@ public Map getInstanceParams() { public String getParameter(String key, String serviceKey) { ServiceInfo serviceInfo = getValidServiceInfo(serviceKey); - if (serviceInfo == null) return null; + if (serviceInfo == null) { + return null; + } return serviceInfo.getParameter(key); } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfoV2.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfoV2.java index 520641396b3..039940c3d61 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfoV2.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfoV2.java @@ -17,6 +17,10 @@ package org.apache.dubbo.metadata; /** + *

+ * Metadata information message.
+ * 
+ * * Protobuf type {@code org.apache.dubbo.metadata.MetadataInfoV2} */ public final class MetadataInfoV2 extends com.google.protobuf.GeneratedMessageV3 @@ -24,6 +28,7 @@ public final class MetadataInfoV2 extends com.google.protobuf.GeneratedMessageV3 // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.MetadataInfoV2) MetadataInfoV2OrBuilder { private static final long serialVersionUID = 0L; + // Use MetadataInfoV2.newBuilder() to construct. private MetadataInfoV2(com.google.protobuf.GeneratedMessageV3.Builder builder) { super(builder); @@ -65,7 +70,12 @@ protected FieldAccessorTable internalGetFieldAccessorTable() { @SuppressWarnings("serial") private volatile Object app_ = ""; + /** + *
+     * The application name.
+     * 
+ * * string app = 1; * @return The app. */ @@ -81,7 +91,12 @@ public String getApp() { return s; } } + /** + *
+     * The application name.
+     * 
+ * * string app = 1; * @return The bytes for app. */ @@ -101,7 +116,12 @@ public com.google.protobuf.ByteString getAppBytes() { @SuppressWarnings("serial") private volatile Object version_ = ""; + /** + *
+     * The application version.
+     * 
+ * * string version = 2; * @return The version. */ @@ -117,7 +137,12 @@ public String getVersion() { return s; } } + /** + *
+     * The application version.
+     * 
+ * * string version = 2; * @return The bytes for version. */ @@ -159,7 +184,12 @@ private com.google.protobuf.MapField internalGetServices( public int getServicesCount() { return internalGetServices().getMap().size(); } + /** + *
+     * A map of service information.
+     * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ @Override @@ -169,6 +199,7 @@ public boolean containsServices(String key) { } return internalGetServices().getMap().containsKey(key); } + /** * Use {@link #getServicesMap()} instead. */ @@ -177,14 +208,24 @@ public boolean containsServices(String key) { public java.util.Map getServices() { return getServicesMap(); } + /** + *
+     * A map of service information.
+     * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ @Override public java.util.Map getServicesMap() { return internalGetServices().getMap(); } + /** + *
+     * A map of service information.
+     * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ @Override @@ -198,7 +239,12 @@ public java.util.Map getServicesMap() { java.util.Map map = internalGetServices().getMap(); return map.containsKey(key) ? map.get(key) : defaultValue; } + /** + *
+     * A map of service information.
+     * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ @Override @@ -218,8 +264,12 @@ public ServiceInfoV2 getServicesOrThrow(String key) { @Override public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; + if (isInitialized == 1) { + return true; + } + if (isInitialized == 0) { + return false; + } memoizedIsInitialized = 1; return true; @@ -241,7 +291,9 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io @Override public int getSerializedSize() { int size = memoizedSize; - if (size != -1) return size; + if (size != -1) { + return size; + } size = 0; if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(app_)) { @@ -274,10 +326,18 @@ public boolean equals(final Object obj) { } MetadataInfoV2 other = (MetadataInfoV2) obj; - if (!getApp().equals(other.getApp())) return false; - if (!getVersion().equals(other.getVersion())) return false; - if (!internalGetServices().equals(other.internalGetServices())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; + if (!getApp().equals(other.getApp())) { + return false; + } + if (!getVersion().equals(other.getVersion())) { + return false; + } + if (!internalGetServices().equals(other.internalGetServices())) { + return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) { + return false; + } return true; } @@ -385,7 +445,12 @@ protected Builder newBuilderForType(BuilderParent parent) { Builder builder = new Builder(parent); return builder; } + /** + *
+     * Metadata information message.
+     * 
+ * * Protobuf type {@code org.apache.dubbo.metadata.MetadataInfoV2} */ public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder @@ -483,6 +548,37 @@ private void buildPartial0(MetadataInfoV2 result) { } } + @Override + public Builder clone() { + return super.clone(); + } + + @Override + public Builder setField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + return super.setField(field, value); + } + + @Override + public Builder clearField(com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + + @Override + public Builder clearOneof(com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, int index, Object value) { + return super.setRepeatedField(field, index, value); + } + + @Override + public Builder addRepeatedField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + return super.addRepeatedField(field, value); + } + @Override public Builder mergeFrom(com.google.protobuf.Message other) { if (other instanceof MetadataInfoV2) { @@ -494,7 +590,9 @@ public Builder mergeFrom(com.google.protobuf.Message other) { } public Builder mergeFrom(MetadataInfoV2 other) { - if (other == MetadataInfoV2.getDefaultInstance()) return this; + if (other == MetadataInfoV2.getDefaultInstance()) { + return this; + } if (!other.getApp().isEmpty()) { app_ = other.app_; bitField0_ |= 0x00000001; @@ -570,7 +668,12 @@ public Builder mergeFrom( private int bitField0_; private Object app_ = ""; + /** + *
+         * The application name.
+         * 
+ * * string app = 1; * @return The app. */ @@ -585,7 +688,12 @@ public String getApp() { return (String) ref; } } + /** + *
+         * The application name.
+         * 
+ * * string app = 1; * @return The bytes for app. */ @@ -599,7 +707,12 @@ public com.google.protobuf.ByteString getAppBytes() { return (com.google.protobuf.ByteString) ref; } } + /** + *
+         * The application name.
+         * 
+ * * string app = 1; * @param value The app to set. * @return This builder for chaining. @@ -613,7 +726,12 @@ public Builder setApp(String value) { onChanged(); return this; } + /** + *
+         * The application name.
+         * 
+ * * string app = 1; * @return This builder for chaining. */ @@ -623,7 +741,12 @@ public Builder clearApp() { onChanged(); return this; } + /** + *
+         * The application name.
+         * 
+ * * string app = 1; * @param value The bytes for app to set. * @return This builder for chaining. @@ -640,7 +763,12 @@ public Builder setAppBytes(com.google.protobuf.ByteString value) { } private Object version_ = ""; + /** + *
+         * The application version.
+         * 
+ * * string version = 2; * @return The version. */ @@ -655,7 +783,12 @@ public String getVersion() { return (String) ref; } } + /** + *
+         * The application version.
+         * 
+ * * string version = 2; * @return The bytes for version. */ @@ -669,7 +802,12 @@ public com.google.protobuf.ByteString getVersionBytes() { return (com.google.protobuf.ByteString) ref; } } + /** + *
+         * The application version.
+         * 
+ * * string version = 2; * @param value The version to set. * @return This builder for chaining. @@ -683,7 +821,12 @@ public Builder setVersion(String value) { onChanged(); return this; } + /** + *
+         * The application version.
+         * 
+ * * string version = 2; * @return This builder for chaining. */ @@ -693,7 +836,12 @@ public Builder clearVersion() { onChanged(); return this; } + /** + *
+         * The application version.
+         * 
+ * * string version = 2; * @param value The bytes for version to set. * @return This builder for chaining. @@ -733,7 +881,12 @@ private com.google.protobuf.MapField internalGetMutableSe public int getServicesCount() { return internalGetServices().getMap().size(); } + /** + *
+         * A map of service information.
+         * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ @Override @@ -743,6 +896,7 @@ public boolean containsServices(String key) { } return internalGetServices().getMap().containsKey(key); } + /** * Use {@link #getServicesMap()} instead. */ @@ -751,14 +905,24 @@ public boolean containsServices(String key) { public java.util.Map getServices() { return getServicesMap(); } + /** + *
+         * A map of service information.
+         * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ @Override public java.util.Map getServicesMap() { return internalGetServices().getMap(); } + /** + *
+         * A map of service information.
+         * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ @Override @@ -772,7 +936,12 @@ public java.util.Map getServicesMap() { java.util.Map map = internalGetServices().getMap(); return map.containsKey(key) ? map.get(key) : defaultValue; } + /** + *
+         * A map of service information.
+         * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ @Override @@ -792,7 +961,12 @@ public Builder clearServices() { internalGetMutableServices().getMutableMap().clear(); return this; } + /** + *
+         * A map of service information.
+         * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ public Builder removeServices(String key) { @@ -802,6 +976,7 @@ public Builder removeServices(String key) { internalGetMutableServices().getMutableMap().remove(key); return this; } + /** * Use alternate mutation accessors instead. */ @@ -810,7 +985,12 @@ public java.util.Map getMutableServices() { bitField0_ |= 0x00000004; return internalGetMutableServices().getMutableMap(); } + /** + *
+         * A map of service information.
+         * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ public Builder putServices(String key, ServiceInfoV2 value) { @@ -824,7 +1004,12 @@ public Builder putServices(String key, ServiceInfoV2 value) { bitField0_ |= 0x00000004; return this; } + /** + *
+         * A map of service information.
+         * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ public Builder putAllServices(java.util.Map values) { diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfoV2OrBuilder.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfoV2OrBuilder.java index cab7cdc934e..adf6b4376fc 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfoV2OrBuilder.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfoV2OrBuilder.java @@ -22,45 +22,83 @@ public interface MetadataInfoV2OrBuilder com.google.protobuf.MessageOrBuilder { /** + *
+     * The application name.
+     * 
+ * * string app = 1; * @return The app. */ String getApp(); + /** + *
+     * The application name.
+     * 
+ * * string app = 1; * @return The bytes for app. */ com.google.protobuf.ByteString getAppBytes(); /** + *
+     * The application version.
+     * 
+ * * string version = 2; * @return The version. */ String getVersion(); + /** + *
+     * The application version.
+     * 
+ * * string version = 2; * @return The bytes for version. */ com.google.protobuf.ByteString getVersionBytes(); /** + *
+     * A map of service information.
+     * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ int getServicesCount(); + /** + *
+     * A map of service information.
+     * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ boolean containsServices(String key); + /** * Use {@link #getServicesMap()} instead. */ @Deprecated java.util.Map getServices(); + /** + *
+     * A map of service information.
+     * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ java.util.Map getServicesMap(); + /** + *
+     * A map of service information.
+     * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ /* nullable */ @@ -68,7 +106,12 @@ ServiceInfoV2 getServicesOrDefault( String key, /* nullable */ ServiceInfoV2 defaultValue); + /** + *
+     * A map of service information.
+     * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ ServiceInfoV2 getServicesOrThrow(String key); diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataRequest.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataRequest.java index c989693c43e..64f191ec087 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataRequest.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataRequest.java @@ -17,6 +17,10 @@ package org.apache.dubbo.metadata; /** + *
+ * Metadata request message.
+ * 
+ * * Protobuf type {@code org.apache.dubbo.metadata.MetadataRequest} */ public final class MetadataRequest extends com.google.protobuf.GeneratedMessageV3 @@ -24,6 +28,7 @@ public final class MetadataRequest extends com.google.protobuf.GeneratedMessageV // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.MetadataRequest) MetadataRequestOrBuilder { private static final long serialVersionUID = 0L; + // Use MetadataRequest.newBuilder() to construct. private MetadataRequest(com.google.protobuf.GeneratedMessageV3.Builder builder) { super(builder); @@ -53,7 +58,12 @@ protected FieldAccessorTable internalGetFieldAccessorTable() { @SuppressWarnings("serial") private volatile Object revision_ = ""; + /** + *
+     * The revision of the metadata.
+     * 
+ * * string revision = 1; * @return The revision. */ @@ -69,7 +79,12 @@ public String getRevision() { return s; } } + /** + *
+     * The revision of the metadata.
+     * 
+ * * string revision = 1; * @return The bytes for revision. */ @@ -90,8 +105,12 @@ public com.google.protobuf.ByteString getRevisionBytes() { @Override public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; + if (isInitialized == 1) { + return true; + } + if (isInitialized == 0) { + return false; + } memoizedIsInitialized = 1; return true; @@ -108,7 +127,9 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io @Override public int getSerializedSize() { int size = memoizedSize; - if (size != -1) return size; + if (size != -1) { + return size; + } size = 0; if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(revision_)) { @@ -129,8 +150,12 @@ public boolean equals(final Object obj) { } MetadataRequest other = (MetadataRequest) obj; - if (!getRevision().equals(other.getRevision())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; + if (!getRevision().equals(other.getRevision())) { + return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) { + return false; + } return true; } @@ -232,7 +257,12 @@ protected Builder newBuilderForType(BuilderParent parent) { Builder builder = new Builder(parent); return builder; } + /** + *
+     * Metadata request message.
+     * 
+ * * Protobuf type {@code org.apache.dubbo.metadata.MetadataRequest} */ public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder @@ -301,6 +331,37 @@ private void buildPartial0(MetadataRequest result) { } } + @Override + public Builder clone() { + return super.clone(); + } + + @Override + public Builder setField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + return super.setField(field, value); + } + + @Override + public Builder clearField(com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + + @Override + public Builder clearOneof(com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, int index, Object value) { + return super.setRepeatedField(field, index, value); + } + + @Override + public Builder addRepeatedField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + return super.addRepeatedField(field, value); + } + @Override public Builder mergeFrom(com.google.protobuf.Message other) { if (other instanceof MetadataRequest) { @@ -312,7 +373,9 @@ public Builder mergeFrom(com.google.protobuf.Message other) { } public Builder mergeFrom(MetadataRequest other) { - if (other == MetadataRequest.getDefaultInstance()) return this; + if (other == MetadataRequest.getDefaultInstance()) { + return this; + } if (!other.getRevision().isEmpty()) { revision_ = other.revision_; bitField0_ |= 0x00000001; @@ -367,7 +430,12 @@ public Builder mergeFrom( private int bitField0_; private Object revision_ = ""; + /** + *
+         * The revision of the metadata.
+         * 
+ * * string revision = 1; * @return The revision. */ @@ -382,7 +450,12 @@ public String getRevision() { return (String) ref; } } + /** + *
+         * The revision of the metadata.
+         * 
+ * * string revision = 1; * @return The bytes for revision. */ @@ -396,7 +469,12 @@ public com.google.protobuf.ByteString getRevisionBytes() { return (com.google.protobuf.ByteString) ref; } } + /** + *
+         * The revision of the metadata.
+         * 
+ * * string revision = 1; * @param value The revision to set. * @return This builder for chaining. @@ -410,7 +488,12 @@ public Builder setRevision(String value) { onChanged(); return this; } + /** + *
+         * The revision of the metadata.
+         * 
+ * * string revision = 1; * @return This builder for chaining. */ @@ -420,7 +503,12 @@ public Builder clearRevision() { onChanged(); return this; } + /** + *
+         * The revision of the metadata.
+         * 
+ * * string revision = 1; * @param value The bytes for revision to set. * @return This builder for chaining. diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataRequestOrBuilder.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataRequestOrBuilder.java index 4099bb21cec..98c54262a1a 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataRequestOrBuilder.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataRequestOrBuilder.java @@ -22,11 +22,20 @@ public interface MetadataRequestOrBuilder com.google.protobuf.MessageOrBuilder { /** + *
+     * The revision of the metadata.
+     * 
+ * * string revision = 1; * @return The revision. */ String getRevision(); + /** + *
+     * The revision of the metadata.
+     * 
+ * * string revision = 1; * @return The bytes for revision. */ diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java index cd767adcad9..30601253a2f 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java @@ -17,6 +17,9 @@ package org.apache.dubbo.metadata; import org.apache.dubbo.common.URL; +import org.apache.dubbo.remoting.http12.rest.Mapping; +import org.apache.dubbo.remoting.http12.rest.OpenAPI; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; import java.util.Collections; import java.util.List; @@ -29,6 +32,7 @@ import static java.util.Collections.unmodifiableSortedSet; import static org.apache.dubbo.common.URL.buildKey; +import static org.apache.dubbo.rpc.Constants.H2_SETTINGS_OPENAPI_PREFIX; /** * This service is used to expose the metadata information inside a Dubbo process. @@ -36,6 +40,7 @@ * 1. The Consumer queries the metadata information of the Provider to list the interfaces and each interface's configuration * 2. The Console (dubbo-admin) queries for the metadata of a specific process, or aggregate data of all processes. */ +@OpenAPI(hidden = "true") public interface MetadataService { /** @@ -200,6 +205,7 @@ static boolean isMetadataService(String interfaceName) { * @param instanceMetadata {@link Map} of provider Service Instance Metadata * @since 3.0 */ + @Mapping(enabled = false) void exportInstanceMetadata(String instanceMetadata); /** @@ -211,6 +217,7 @@ static boolean isMetadataService(String interfaceName) { * @return {@link Map} of {@link InstanceMetadataChangedListener} * @since 3.0 */ + @Mapping(enabled = false) Map getInstanceMetadataChangedListenerMap(); /** @@ -225,5 +232,12 @@ static boolean isMetadataService(String interfaceName) { * @return {@link Map} of provider Service Instance Metadata * @since 3.0 */ + @Mapping(enabled = false) String getAndListenInstanceMetadata(String consumerId, InstanceMetadataChangedListener listener); + + /** + * 1. Get the openAPI definition + */ + @Mapping("//${" + H2_SETTINGS_OPENAPI_PREFIX + ".path:dubbo/openapi}/{*path}") + String getOpenAPI(OpenAPIRequest request); } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java index d85df91a140..54278b165b8 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java @@ -23,7 +23,21 @@ public interface MetadataServiceV2 extends org.apache.dubbo.rpc.model.DubboStub String JAVA_SERVICE_NAME = "org.apache.dubbo.metadata.MetadataServiceV2"; String SERVICE_NAME = "org.apache.dubbo.metadata.MetadataServiceV2"; + /** + *
+     *  Retrieves metadata information.
+     * 
+ */ MetadataInfoV2 getMetadataInfo(MetadataRequest request); CompletableFuture getMetadataInfoAsync(MetadataRequest request); + + /** + *
+     *  Retrieves OpenAPI information.
+     * 
+ */ + OpenAPIInfo getOpenAPIInfo(OpenAPIRequest request); + + CompletableFuture getOpenAPIInfoAsync(OpenAPIRequest request); } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2Detector.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2Detector.java index 59962281568..171b370ab5e 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2Detector.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2Detector.java @@ -18,6 +18,7 @@ import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.ClassUtils; import org.apache.dubbo.rpc.model.BuiltinServiceDetector; public class MetadataServiceV2Detector implements BuiltinServiceDetector { @@ -29,20 +30,14 @@ public class MetadataServiceV2Detector implements BuiltinServiceDetector { @Override public Class getService() { - if (!support()) { - logger.info( - "To use MetadataServiceV2, Protobuf dependencies are required. Fallback to MetadataService(V1)."); - return null; + if (ClassUtils.hasProtobuf()) { + return MetadataServiceV2.class; } - return org.apache.dubbo.metadata.MetadataServiceV2.class; + logger.info("To use MetadataServiceV2, Protobuf dependencies are required. Fallback to MetadataService(V1)."); + return null; } public static boolean support() { - try { - Class.forName("com.google.protobuf.Message"); - } catch (ClassNotFoundException classNotFoundException) { - return false; - } - return true; + return ClassUtils.hasProtobuf(); } } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2OuterClass.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2OuterClass.java index 01c1362d70e..fd1635a6ec1 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2OuterClass.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2OuterClass.java @@ -45,6 +45,14 @@ public static void registerAllExtensions(com.google.protobuf.ExtensionRegistry r internal_static_org_apache_dubbo_metadata_ServiceInfoV2_ParamsEntry_descriptor; static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_org_apache_dubbo_metadata_ServiceInfoV2_ParamsEntry_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_org_apache_dubbo_metadata_OpenAPIRequest_descriptor; + static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_org_apache_dubbo_metadata_OpenAPIRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_org_apache_dubbo_metadata_OpenAPIInfo_descriptor; + static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_org_apache_dubbo_metadata_OpenAPIInfo_fieldAccessorTable; public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { return descriptor; @@ -67,12 +75,22 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { + "(\005\022\014\n\004path\030\006 \001(\t\022D\n\006params\030\007 \003(\01324.org.a" + "pache.dubbo.metadata.ServiceInfoV2.Param" + "sEntry\032-\n\013ParamsEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005va" - + "lue\030\002 \001(\t:\0028\0012}\n\021MetadataServiceV2\022h\n\017Ge" - + "tMetadataInfo\022*.org.apache.dubbo.metadat" - + "a.MetadataRequest\032).org.apache.dubbo.met" - + "adata.MetadataInfoV2BZ\n\031org.apache.dubbo" - + ".metadataP\001Z;dubbo.apache.org/dubbo-go/v" - + "3/metadata/triple_api;triple_apib\006proto3" + + "lue\030\002 \001(\t:\0028\001\"\311\001\n\016OpenAPIRequest\022\r\n\005grou" + + "p\030\001 \001(\t\022\017\n\007version\030\002 \001(\t\022\013\n\003tag\030\003 \003(\t\022\017\n" + + "\007service\030\004 \003(\t\022\017\n\007openapi\030\005 \001(\t\022=\n\006forma" + + "t\030\006 \001(\0162(.org.apache.dubbo.metadata.Open" + + "APIFormatH\000\210\001\001\022\023\n\006pretty\030\007 \001(\010H\001\210\001\001B\t\n\007_" + + "formatB\t\n\007_pretty\"!\n\013OpenAPIInfo\022\022\n\ndefi" + + "nition\030\001 \001(\t*.\n\rOpenAPIFormat\022\010\n\004JSON\020\000\022" + + "\010\n\004YAML\020\001\022\t\n\005PROTO\020\0022\342\001\n\021MetadataService" + + "V2\022h\n\017GetMetadataInfo\022*.org.apache.dubbo" + + ".metadata.MetadataRequest\032).org.apache.d" + + "ubbo.metadata.MetadataInfoV2\022c\n\016GetOpenA" + + "PIInfo\022).org.apache.dubbo.metadata.OpenA" + + "PIRequest\032&.org.apache.dubbo.metadata.Op" + + "enAPIInfoBZ\n\031org.apache.dubbo.metadataP\001" + + "Z;dubbo.apache.org/dubbo-go/v3/metadata/" + + "triple_api;triple_apib\006proto3" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom( descriptorData, new com.google.protobuf.Descriptors.FileDescriptor[] {}); @@ -116,6 +134,20 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { internal_static_org_apache_dubbo_metadata_ServiceInfoV2_ParamsEntry_descriptor, new String[] { "Key", "Value", }); + internal_static_org_apache_dubbo_metadata_OpenAPIRequest_descriptor = + getDescriptor().getMessageTypes().get(3); + internal_static_org_apache_dubbo_metadata_OpenAPIRequest_fieldAccessorTable = + new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_org_apache_dubbo_metadata_OpenAPIRequest_descriptor, new String[] { + "Group", "Version", "Tag", "Service", "Openapi", "Format", "Pretty", "Format", "Pretty", + }); + internal_static_org_apache_dubbo_metadata_OpenAPIInfo_descriptor = + getDescriptor().getMessageTypes().get(4); + internal_static_org_apache_dubbo_metadata_OpenAPIInfo_fieldAccessorTable = + new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_org_apache_dubbo_metadata_OpenAPIInfo_descriptor, new String[] { + "Definition", + }); } // @@protoc_insertion_point(outer_class_scope) diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIFormat.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIFormat.java new file mode 100644 index 00000000000..f679ee9b7ab --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIFormat.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.dubbo.metadata; + +/** + *
+ * Response format enumeration.
+ * 
+ * + * Protobuf enum {@code org.apache.dubbo.metadata.OpenAPIFormat} + */ +public enum OpenAPIFormat implements com.google.protobuf.ProtocolMessageEnum { + /** + *
+     * JSON format.
+     * 
+ * + * JSON = 0; + */ + JSON(0), + /** + *
+     * YAML format.
+     * 
+ * + * YAML = 1; + */ + YAML(1), + /** + *
+     * PROTO format.
+     * 
+ * + * PROTO = 2; + */ + PROTO(2), + UNRECOGNIZED(-1), + ; + + /** + *
+     * JSON format.
+     * 
+ * + * JSON = 0; + */ + public static final int JSON_VALUE = 0; + /** + *
+     * YAML format.
+     * 
+ * + * YAML = 1; + */ + public static final int YAML_VALUE = 1; + /** + *
+     * PROTO format.
+     * 
+ * + * PROTO = 2; + */ + public static final int PROTO_VALUE = 2; + + public final int getNumber() { + if (this == UNRECOGNIZED) { + throw new IllegalArgumentException("Can't get the number of an unknown enum value."); + } + return value; + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @Deprecated + public static OpenAPIFormat valueOf(int value) { + return forNumber(value); + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + */ + public static OpenAPIFormat forNumber(int value) { + switch (value) { + case 0: + return JSON; + case 1: + return YAML; + case 2: + return PROTO; + default: + return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap internalGetValueMap() { + return internalValueMap; + } + + private static final com.google.protobuf.Internal.EnumLiteMap internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public OpenAPIFormat findValueByNumber(int number) { + return OpenAPIFormat.forNumber(number); + } + }; + + public final com.google.protobuf.Descriptors.EnumValueDescriptor getValueDescriptor() { + if (this == UNRECOGNIZED) { + throw new IllegalStateException("Can't get the descriptor of an unrecognized enum value."); + } + 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 MetadataServiceV2OuterClass.getDescriptor().getEnumTypes().get(0); + } + + private static final OpenAPIFormat[] VALUES = values(); + + public static OpenAPIFormat 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 OpenAPIFormat(int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:org.apache.dubbo.metadata.OpenAPIFormat) +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIInfo.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIInfo.java new file mode 100644 index 00000000000..03d25d30b38 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIInfo.java @@ -0,0 +1,585 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata; + +/** + *
+ * OpenAPI information message.
+ * 
+ * + * Protobuf type {@code org.apache.dubbo.metadata.OpenAPIInfo} + */ +public final class OpenAPIInfo extends com.google.protobuf.GeneratedMessageV3 + implements + // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.OpenAPIInfo) + OpenAPIInfoOrBuilder { + private static final long serialVersionUID = 0L; + + // Use OpenAPIInfo.newBuilder() to construct. + private OpenAPIInfo(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + + private OpenAPIInfo() { + definition_ = ""; + } + + @Override + @SuppressWarnings({"unused"}) + protected Object newInstance(UnusedPrivateParameter unused) { + return new OpenAPIInfo(); + } + + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIInfo_descriptor; + } + + @Override + protected FieldAccessorTable internalGetFieldAccessorTable() { + return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIInfo_fieldAccessorTable + .ensureFieldAccessorsInitialized(OpenAPIInfo.class, Builder.class); + } + + public static final int DEFINITION_FIELD_NUMBER = 1; + + @SuppressWarnings("serial") + private volatile Object definition_ = ""; + + /** + *
+     * The OpenAPI definition.
+     * 
+ * + * string definition = 1; + * @return The definition. + */ + @Override + public String getDefinition() { + Object ref = definition_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + definition_ = s; + return s; + } + } + + /** + *
+     * The OpenAPI definition.
+     * 
+ * + * string definition = 1; + * @return The bytes for definition. + */ + @Override + public com.google.protobuf.ByteString getDefinitionBytes() { + Object ref = definition_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref); + definition_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + 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 (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(definition_)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, definition_); + } + getUnknownFields().writeTo(output); + } + + @Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) { + return size; + } + + size = 0; + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(definition_)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, definition_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof OpenAPIInfo)) { + return super.equals(obj); + } + OpenAPIInfo other = (OpenAPIInfo) obj; + + if (!getDefinition().equals(other.getDefinition())) { + return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) { + return false; + } + return true; + } + + @Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + DEFINITION_FIELD_NUMBER; + hash = (53 * hash) + getDefinition().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static OpenAPIInfo parseFrom(java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static OpenAPIInfo parseFrom( + java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static OpenAPIInfo parseFrom(com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static OpenAPIInfo parseFrom( + com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static OpenAPIInfo parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static OpenAPIInfo parseFrom(byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static OpenAPIInfo parseFrom(java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input); + } + + public static OpenAPIInfo 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 OpenAPIInfo parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input); + } + + public static OpenAPIInfo 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 OpenAPIInfo parseFrom(com.google.protobuf.CodedInputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input); + } + + public static OpenAPIInfo 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(OpenAPIInfo 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; + } + + /** + *
+     * OpenAPI information message.
+     * 
+ * + * Protobuf type {@code org.apache.dubbo.metadata.OpenAPIInfo} + */ + public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder + implements + // @@protoc_insertion_point(builder_implements:org.apache.dubbo.metadata.OpenAPIInfo) + OpenAPIInfoOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIInfo_descriptor; + } + + @Override + protected FieldAccessorTable internalGetFieldAccessorTable() { + return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIInfo_fieldAccessorTable + .ensureFieldAccessorsInitialized(OpenAPIInfo.class, Builder.class); + } + + // Construct using org.apache.dubbo.metadata.OpenAPIInfo.newBuilder() + private Builder() {} + + private Builder(BuilderParent parent) { + super(parent); + } + + @Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + definition_ = ""; + return this; + } + + @Override + public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { + return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIInfo_descriptor; + } + + @Override + public OpenAPIInfo getDefaultInstanceForType() { + return OpenAPIInfo.getDefaultInstance(); + } + + @Override + public OpenAPIInfo build() { + OpenAPIInfo result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @Override + public OpenAPIInfo buildPartial() { + OpenAPIInfo result = new OpenAPIInfo(this); + if (bitField0_ != 0) { + buildPartial0(result); + } + onBuilt(); + return result; + } + + private void buildPartial0(OpenAPIInfo result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.definition_ = definition_; + } + } + + @Override + public Builder clone() { + return super.clone(); + } + + @Override + public Builder setField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + return super.setField(field, value); + } + + @Override + public Builder clearField(com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + + @Override + public Builder clearOneof(com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, int index, Object value) { + return super.setRepeatedField(field, index, value); + } + + @Override + public Builder addRepeatedField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + return super.addRepeatedField(field, value); + } + + @Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof OpenAPIInfo) { + return mergeFrom((OpenAPIInfo) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(OpenAPIInfo other) { + if (other == OpenAPIInfo.getDefaultInstance()) { + return this; + } + if (!other.getDefinition().isEmpty()) { + definition_ = other.definition_; + bitField0_ |= 0x00000001; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + 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 { + if (extensionRegistry == null) { + throw new NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + definition_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + + private int bitField0_; + + private Object definition_ = ""; + + /** + *
+         * The OpenAPI definition.
+         * 
+ * + * string definition = 1; + * @return The definition. + */ + public String getDefinition() { + Object ref = definition_; + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + definition_ = s; + return s; + } else { + return (String) ref; + } + } + + /** + *
+         * The OpenAPI definition.
+         * 
+ * + * string definition = 1; + * @return The bytes for definition. + */ + public com.google.protobuf.ByteString getDefinitionBytes() { + Object ref = definition_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref); + definition_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + /** + *
+         * The OpenAPI definition.
+         * 
+ * + * string definition = 1; + * @param value The definition to set. + * @return This builder for chaining. + */ + public Builder setDefinition(String value) { + if (value == null) { + throw new NullPointerException(); + } + definition_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + /** + *
+         * The OpenAPI definition.
+         * 
+ * + * string definition = 1; + * @return This builder for chaining. + */ + public Builder clearDefinition() { + definition_ = getDefaultInstance().getDefinition(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + + /** + *
+         * The OpenAPI definition.
+         * 
+ * + * string definition = 1; + * @param value The bytes for definition to set. + * @return This builder for chaining. + */ + public Builder setDefinitionBytes(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + definition_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + @Override + public final Builder setUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @Override + public final Builder mergeUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + // @@protoc_insertion_point(builder_scope:org.apache.dubbo.metadata.OpenAPIInfo) + } + + // @@protoc_insertion_point(class_scope:org.apache.dubbo.metadata.OpenAPIInfo) + private static final OpenAPIInfo DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new OpenAPIInfo(); + } + + public static OpenAPIInfo getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + @Override + public OpenAPIInfo parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @Override + public OpenAPIInfo getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIInfoOrBuilder.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIInfoOrBuilder.java new file mode 100644 index 00000000000..17540e1df73 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIInfoOrBuilder.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.dubbo.metadata; + +public interface OpenAPIInfoOrBuilder + extends + // @@protoc_insertion_point(interface_extends:org.apache.dubbo.metadata.OpenAPIInfo) + com.google.protobuf.MessageOrBuilder { + + /** + *
+     * The OpenAPI definition.
+     * 
+ * + * string definition = 1; + * @return The definition. + */ + String getDefinition(); + + /** + *
+     * The OpenAPI definition.
+     * 
+ * + * string definition = 1; + * @return The bytes for definition. + */ + com.google.protobuf.ByteString getDefinitionBytes(); +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIRequest.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIRequest.java new file mode 100644 index 00000000000..cb15b273e3a --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIRequest.java @@ -0,0 +1,1746 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata; + +/** + *
+ * OpenAPI request message.
+ * 
+ * + * Protobuf type {@code org.apache.dubbo.metadata.OpenAPIRequest} + */ +public final class OpenAPIRequest extends com.google.protobuf.GeneratedMessageV3 + implements + // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.OpenAPIRequest) + OpenAPIRequestOrBuilder { + private static final long serialVersionUID = 0L; + + // Use OpenAPIRequest.newBuilder() to construct. + private OpenAPIRequest(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + + private OpenAPIRequest() { + group_ = ""; + version_ = ""; + tag_ = com.google.protobuf.LazyStringArrayList.emptyList(); + service_ = com.google.protobuf.LazyStringArrayList.emptyList(); + openapi_ = ""; + format_ = 0; + } + + @Override + @SuppressWarnings({"unused"}) + protected Object newInstance(UnusedPrivateParameter unused) { + return new OpenAPIRequest(); + } + + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIRequest_descriptor; + } + + @Override + protected FieldAccessorTable internalGetFieldAccessorTable() { + return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized(OpenAPIRequest.class, Builder.class); + } + + private int bitField0_; + public static final int GROUP_FIELD_NUMBER = 1; + + @SuppressWarnings("serial") + private volatile Object group_ = ""; + + /** + *
+     * The openAPI group.
+     * 
+ * + * string group = 1; + * @return The group. + */ + @Override + public String getGroup() { + Object ref = group_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + group_ = s; + return s; + } + } + + /** + *
+     * The openAPI group.
+     * 
+ * + * string group = 1; + * @return The bytes for group. + */ + @Override + public com.google.protobuf.ByteString getGroupBytes() { + Object ref = group_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref); + group_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int VERSION_FIELD_NUMBER = 2; + + @SuppressWarnings("serial") + private volatile Object version_ = ""; + + /** + *
+     * The openAPI version, using a major.minor.patch versioning scheme
+     * e.g. 1.0.1
+     * 
+ * + * string version = 2; + * @return The version. + */ + @Override + public String getVersion() { + Object ref = version_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + version_ = s; + return s; + } + } + + /** + *
+     * The openAPI version, using a major.minor.patch versioning scheme
+     * e.g. 1.0.1
+     * 
+ * + * string version = 2; + * @return The bytes for version. + */ + @Override + public com.google.protobuf.ByteString getVersionBytes() { + Object ref = version_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref); + version_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int TAG_FIELD_NUMBER = 3; + + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList tag_ = com.google.protobuf.LazyStringArrayList.emptyList(); + + /** + *
+     * The openAPI tags. Each tag is an or condition.
+     * 
+ * + * repeated string tag = 3; + * @return A list containing the tag. + */ + public com.google.protobuf.ProtocolStringList getTagList() { + return tag_; + } + + /** + *
+     * The openAPI tags. Each tag is an or condition.
+     * 
+ * + * repeated string tag = 3; + * @return The count of tag. + */ + public int getTagCount() { + return tag_.size(); + } + + /** + *
+     * The openAPI tags. Each tag is an or condition.
+     * 
+ * + * repeated string tag = 3; + * @param index The index of the element to return. + * @return The tag at the given index. + */ + public String getTag(int index) { + return tag_.get(index); + } + + /** + *
+     * The openAPI tags. Each tag is an or condition.
+     * 
+ * + * repeated string tag = 3; + * @param index The index of the value to return. + * @return The bytes of the tag at the given index. + */ + public com.google.protobuf.ByteString getTagBytes(int index) { + return tag_.getByteString(index); + } + + public static final int SERVICE_FIELD_NUMBER = 4; + + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList service_ = com.google.protobuf.LazyStringArrayList.emptyList(); + + /** + *
+     * The openAPI services. Each service is an or condition.
+     * 
+ * + * repeated string service = 4; + * @return A list containing the service. + */ + public com.google.protobuf.ProtocolStringList getServiceList() { + return service_; + } + + /** + *
+     * The openAPI services. Each service is an or condition.
+     * 
+ * + * repeated string service = 4; + * @return The count of service. + */ + public int getServiceCount() { + return service_.size(); + } + + /** + *
+     * The openAPI services. Each service is an or condition.
+     * 
+ * + * repeated string service = 4; + * @param index The index of the element to return. + * @return The service at the given index. + */ + public String getService(int index) { + return service_.get(index); + } + + /** + *
+     * The openAPI services. Each service is an or condition.
+     * 
+ * + * repeated string service = 4; + * @param index The index of the value to return. + * @return The bytes of the service at the given index. + */ + public com.google.protobuf.ByteString getServiceBytes(int index) { + return service_.getByteString(index); + } + + public static final int OPENAPI_FIELD_NUMBER = 5; + + @SuppressWarnings("serial") + private volatile Object openapi_ = ""; + + /** + *
+     * The openAPI specification version, using a major.minor.patch versioning scheme
+     * e.g. 3.0.1, 3.1.0
+     * The default value is '3.0.1'.
+     * 
+ * + * string openapi = 5; + * @return The openapi. + */ + @Override + public String getOpenapi() { + Object ref = openapi_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + openapi_ = s; + return s; + } + } + + /** + *
+     * The openAPI specification version, using a major.minor.patch versioning scheme
+     * e.g. 3.0.1, 3.1.0
+     * The default value is '3.0.1'.
+     * 
+ * + * string openapi = 5; + * @return The bytes for openapi. + */ + @Override + public com.google.protobuf.ByteString getOpenapiBytes() { + Object ref = openapi_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref); + openapi_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int FORMAT_FIELD_NUMBER = 6; + private int format_ = 0; + + /** + *
+     * The format of the response.
+     * The default value is 'JSON'.
+     * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @return Whether the format field is set. + */ + @Override + public boolean hasFormat() { + return ((bitField0_ & 0x00000001) != 0); + } + + /** + *
+     * The format of the response.
+     * The default value is 'JSON'.
+     * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @return The enum numeric value on the wire for format. + */ + @Override + public int getFormatValue() { + return format_; + } + + /** + *
+     * The format of the response.
+     * The default value is 'JSON'.
+     * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @return The format. + */ + @Override + public OpenAPIFormat getFormat() { + OpenAPIFormat result = OpenAPIFormat.forNumber(format_); + return result == null ? OpenAPIFormat.UNRECOGNIZED : result; + } + + public static final int PRETTY_FIELD_NUMBER = 7; + private boolean pretty_ = false; + + /** + *
+     * Whether to pretty print for json.
+     * The default value is 'false'.
+     * 
+ * + * optional bool pretty = 7; + * @return Whether the pretty field is set. + */ + @Override + public boolean hasPretty() { + return ((bitField0_ & 0x00000002) != 0); + } + + /** + *
+     * Whether to pretty print for json.
+     * The default value is 'false'.
+     * 
+ * + * optional bool pretty = 7; + * @return The pretty. + */ + @Override + public boolean getPretty() { + return pretty_; + } + + 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 (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(group_)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, group_); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(version_)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 2, version_); + } + for (int i = 0; i < tag_.size(); i++) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 3, tag_.getRaw(i)); + } + for (int i = 0; i < service_.size(); i++) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 4, service_.getRaw(i)); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(openapi_)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 5, openapi_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeEnum(6, format_); + } + if (((bitField0_ & 0x00000002) != 0)) { + output.writeBool(7, pretty_); + } + getUnknownFields().writeTo(output); + } + + @Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) { + return size; + } + + size = 0; + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(group_)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, group_); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(version_)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, version_); + } + { + int dataSize = 0; + for (int i = 0; i < tag_.size(); i++) { + dataSize += computeStringSizeNoTag(tag_.getRaw(i)); + } + size += dataSize; + size += 1 * getTagList().size(); + } + { + int dataSize = 0; + for (int i = 0; i < service_.size(); i++) { + dataSize += computeStringSizeNoTag(service_.getRaw(i)); + } + size += dataSize; + size += 1 * getServiceList().size(); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(openapi_)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(5, openapi_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream.computeEnumSize(6, format_); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.CodedOutputStream.computeBoolSize(7, pretty_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof OpenAPIRequest)) { + return super.equals(obj); + } + OpenAPIRequest other = (OpenAPIRequest) obj; + + if (!getGroup().equals(other.getGroup())) { + return false; + } + if (!getVersion().equals(other.getVersion())) { + return false; + } + if (!getTagList().equals(other.getTagList())) { + return false; + } + if (!getServiceList().equals(other.getServiceList())) { + return false; + } + if (!getOpenapi().equals(other.getOpenapi())) { + return false; + } + if (hasFormat() != other.hasFormat()) { + return false; + } + if (hasFormat()) { + if (format_ != other.format_) { + return false; + } + } + if (hasPretty() != other.hasPretty()) { + return false; + } + if (hasPretty()) { + if (getPretty() != other.getPretty()) { + return false; + } + } + if (!getUnknownFields().equals(other.getUnknownFields())) { + return false; + } + return true; + } + + @Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + GROUP_FIELD_NUMBER; + hash = (53 * hash) + getGroup().hashCode(); + hash = (37 * hash) + VERSION_FIELD_NUMBER; + hash = (53 * hash) + getVersion().hashCode(); + if (getTagCount() > 0) { + hash = (37 * hash) + TAG_FIELD_NUMBER; + hash = (53 * hash) + getTagList().hashCode(); + } + if (getServiceCount() > 0) { + hash = (37 * hash) + SERVICE_FIELD_NUMBER; + hash = (53 * hash) + getServiceList().hashCode(); + } + hash = (37 * hash) + OPENAPI_FIELD_NUMBER; + hash = (53 * hash) + getOpenapi().hashCode(); + if (hasFormat()) { + hash = (37 * hash) + FORMAT_FIELD_NUMBER; + hash = (53 * hash) + format_; + } + if (hasPretty()) { + hash = (37 * hash) + PRETTY_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean(getPretty()); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static OpenAPIRequest parseFrom(java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static OpenAPIRequest parseFrom( + java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static OpenAPIRequest parseFrom(com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static OpenAPIRequest parseFrom( + com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static OpenAPIRequest parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static OpenAPIRequest parseFrom(byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static OpenAPIRequest parseFrom(java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input); + } + + public static OpenAPIRequest 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 OpenAPIRequest parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input); + } + + public static OpenAPIRequest 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 OpenAPIRequest parseFrom(com.google.protobuf.CodedInputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input); + } + + public static OpenAPIRequest 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(OpenAPIRequest 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; + } + + /** + *
+     * OpenAPI request message.
+     * 
+ * + * Protobuf type {@code org.apache.dubbo.metadata.OpenAPIRequest} + */ + public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder + implements + // @@protoc_insertion_point(builder_implements:org.apache.dubbo.metadata.OpenAPIRequest) + OpenAPIRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIRequest_descriptor; + } + + @Override + protected FieldAccessorTable internalGetFieldAccessorTable() { + return MetadataServiceV2OuterClass + .internal_static_org_apache_dubbo_metadata_OpenAPIRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized(OpenAPIRequest.class, Builder.class); + } + + // Construct using org.apache.dubbo.metadata.OpenAPIRequest.newBuilder() + private Builder() {} + + private Builder(BuilderParent parent) { + super(parent); + } + + @Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + group_ = ""; + version_ = ""; + tag_ = com.google.protobuf.LazyStringArrayList.emptyList(); + service_ = com.google.protobuf.LazyStringArrayList.emptyList(); + openapi_ = ""; + format_ = 0; + pretty_ = false; + return this; + } + + @Override + public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { + return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIRequest_descriptor; + } + + @Override + public OpenAPIRequest getDefaultInstanceForType() { + return OpenAPIRequest.getDefaultInstance(); + } + + @Override + public OpenAPIRequest build() { + OpenAPIRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @Override + public OpenAPIRequest buildPartial() { + OpenAPIRequest result = new OpenAPIRequest(this); + if (bitField0_ != 0) { + buildPartial0(result); + } + onBuilt(); + return result; + } + + private void buildPartial0(OpenAPIRequest result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.group_ = group_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.version_ = version_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + tag_.makeImmutable(); + result.tag_ = tag_; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + service_.makeImmutable(); + result.service_ = service_; + } + if (((from_bitField0_ & 0x00000010) != 0)) { + result.openapi_ = openapi_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000020) != 0)) { + result.format_ = format_; + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000040) != 0)) { + result.pretty_ = pretty_; + to_bitField0_ |= 0x00000002; + } + result.bitField0_ |= to_bitField0_; + } + + @Override + public Builder clone() { + return super.clone(); + } + + @Override + public Builder setField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + return super.setField(field, value); + } + + @Override + public Builder clearField(com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + + @Override + public Builder clearOneof(com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, int index, Object value) { + return super.setRepeatedField(field, index, value); + } + + @Override + public Builder addRepeatedField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + return super.addRepeatedField(field, value); + } + + @Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof OpenAPIRequest) { + return mergeFrom((OpenAPIRequest) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(OpenAPIRequest other) { + if (other == OpenAPIRequest.getDefaultInstance()) { + return this; + } + if (!other.getGroup().isEmpty()) { + group_ = other.group_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getVersion().isEmpty()) { + version_ = other.version_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.tag_.isEmpty()) { + if (tag_.isEmpty()) { + tag_ = other.tag_; + bitField0_ |= 0x00000004; + } else { + ensureTagIsMutable(); + tag_.addAll(other.tag_); + } + onChanged(); + } + if (!other.service_.isEmpty()) { + if (service_.isEmpty()) { + service_ = other.service_; + bitField0_ |= 0x00000008; + } else { + ensureServiceIsMutable(); + service_.addAll(other.service_); + } + onChanged(); + } + if (!other.getOpenapi().isEmpty()) { + openapi_ = other.openapi_; + bitField0_ |= 0x00000010; + onChanged(); + } + if (other.hasFormat()) { + setFormat(other.getFormat()); + } + if (other.hasPretty()) { + setPretty(other.getPretty()); + } + this.mergeUnknownFields(other.getUnknownFields()); + 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 { + if (extensionRegistry == null) { + throw new NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + group_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + version_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + String s = input.readStringRequireUtf8(); + ensureTagIsMutable(); + tag_.add(s); + break; + } // case 26 + case 34: { + String s = input.readStringRequireUtf8(); + ensureServiceIsMutable(); + service_.add(s); + break; + } // case 34 + case 42: { + openapi_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000010; + break; + } // case 42 + case 48: { + format_ = input.readEnum(); + bitField0_ |= 0x00000020; + break; + } // case 48 + case 56: { + pretty_ = input.readBool(); + bitField0_ |= 0x00000040; + break; + } // case 56 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + + private int bitField0_; + + private Object group_ = ""; + + /** + *
+         * The openAPI group.
+         * 
+ * + * string group = 1; + * @return The group. + */ + public String getGroup() { + Object ref = group_; + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + group_ = s; + return s; + } else { + return (String) ref; + } + } + + /** + *
+         * The openAPI group.
+         * 
+ * + * string group = 1; + * @return The bytes for group. + */ + public com.google.protobuf.ByteString getGroupBytes() { + Object ref = group_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref); + group_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + /** + *
+         * The openAPI group.
+         * 
+ * + * string group = 1; + * @param value The group to set. + * @return This builder for chaining. + */ + public Builder setGroup(String value) { + if (value == null) { + throw new NullPointerException(); + } + group_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + /** + *
+         * The openAPI group.
+         * 
+ * + * string group = 1; + * @return This builder for chaining. + */ + public Builder clearGroup() { + group_ = getDefaultInstance().getGroup(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + + /** + *
+         * The openAPI group.
+         * 
+ * + * string group = 1; + * @param value The bytes for group to set. + * @return This builder for chaining. + */ + public Builder setGroupBytes(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + group_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private Object version_ = ""; + + /** + *
+         * The openAPI version, using a major.minor.patch versioning scheme
+         * e.g. 1.0.1
+         * 
+ * + * string version = 2; + * @return The version. + */ + public String getVersion() { + Object ref = version_; + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + version_ = s; + return s; + } else { + return (String) ref; + } + } + + /** + *
+         * The openAPI version, using a major.minor.patch versioning scheme
+         * e.g. 1.0.1
+         * 
+ * + * string version = 2; + * @return The bytes for version. + */ + public com.google.protobuf.ByteString getVersionBytes() { + Object ref = version_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref); + version_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + /** + *
+         * The openAPI version, using a major.minor.patch versioning scheme
+         * e.g. 1.0.1
+         * 
+ * + * string version = 2; + * @param value The version to set. + * @return This builder for chaining. + */ + public Builder setVersion(String value) { + if (value == null) { + throw new NullPointerException(); + } + version_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + /** + *
+         * The openAPI version, using a major.minor.patch versioning scheme
+         * e.g. 1.0.1
+         * 
+ * + * string version = 2; + * @return This builder for chaining. + */ + public Builder clearVersion() { + version_ = getDefaultInstance().getVersion(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + + /** + *
+         * The openAPI version, using a major.minor.patch versioning scheme
+         * e.g. 1.0.1
+         * 
+ * + * string version = 2; + * @param value The bytes for version to set. + * @return This builder for chaining. + */ + public Builder setVersionBytes(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + version_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private com.google.protobuf.LazyStringArrayList tag_ = com.google.protobuf.LazyStringArrayList.emptyList(); + + private void ensureTagIsMutable() { + if (!tag_.isModifiable()) { + tag_ = new com.google.protobuf.LazyStringArrayList(tag_); + } + bitField0_ |= 0x00000004; + } + + /** + *
+         * The openAPI tags. Each tag is an or condition.
+         * 
+ * + * repeated string tag = 3; + * @return A list containing the tag. + */ + public com.google.protobuf.ProtocolStringList getTagList() { + tag_.makeImmutable(); + return tag_; + } + + /** + *
+         * The openAPI tags. Each tag is an or condition.
+         * 
+ * + * repeated string tag = 3; + * @return The count of tag. + */ + public int getTagCount() { + return tag_.size(); + } + + /** + *
+         * The openAPI tags. Each tag is an or condition.
+         * 
+ * + * repeated string tag = 3; + * @param index The index of the element to return. + * @return The tag at the given index. + */ + public String getTag(int index) { + return tag_.get(index); + } + + /** + *
+         * The openAPI tags. Each tag is an or condition.
+         * 
+ * + * repeated string tag = 3; + * @param index The index of the value to return. + * @return The bytes of the tag at the given index. + */ + public com.google.protobuf.ByteString getTagBytes(int index) { + return tag_.getByteString(index); + } + + /** + *
+         * The openAPI tags. Each tag is an or condition.
+         * 
+ * + * repeated string tag = 3; + * @param index The index to set the value at. + * @param value The tag to set. + * @return This builder for chaining. + */ + public Builder setTag(int index, String value) { + if (value == null) { + throw new NullPointerException(); + } + ensureTagIsMutable(); + tag_.set(index, value); + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + /** + *
+         * The openAPI tags. Each tag is an or condition.
+         * 
+ * + * repeated string tag = 3; + * @param value The tag to add. + * @return This builder for chaining. + */ + public Builder addTag(String value) { + if (value == null) { + throw new NullPointerException(); + } + ensureTagIsMutable(); + tag_.add(value); + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + /** + *
+         * The openAPI tags. Each tag is an or condition.
+         * 
+ * + * repeated string tag = 3; + * @param values The tag to add. + * @return This builder for chaining. + */ + public Builder addAllTag(Iterable values) { + ensureTagIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll(values, tag_); + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + /** + *
+         * The openAPI tags. Each tag is an or condition.
+         * 
+ * + * repeated string tag = 3; + * @return This builder for chaining. + */ + public Builder clearTag() { + tag_ = com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000004); + ; + onChanged(); + return this; + } + + /** + *
+         * The openAPI tags. Each tag is an or condition.
+         * 
+ * + * repeated string tag = 3; + * @param value The bytes of the tag to add. + * @return This builder for chaining. + */ + public Builder addTagBytes(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + ensureTagIsMutable(); + tag_.add(value); + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + private com.google.protobuf.LazyStringArrayList service_ = com.google.protobuf.LazyStringArrayList.emptyList(); + + private void ensureServiceIsMutable() { + if (!service_.isModifiable()) { + service_ = new com.google.protobuf.LazyStringArrayList(service_); + } + bitField0_ |= 0x00000008; + } + + /** + *
+         * The openAPI services. Each service is an or condition.
+         * 
+ * + * repeated string service = 4; + * @return A list containing the service. + */ + public com.google.protobuf.ProtocolStringList getServiceList() { + service_.makeImmutable(); + return service_; + } + + /** + *
+         * The openAPI services. Each service is an or condition.
+         * 
+ * + * repeated string service = 4; + * @return The count of service. + */ + public int getServiceCount() { + return service_.size(); + } + + /** + *
+         * The openAPI services. Each service is an or condition.
+         * 
+ * + * repeated string service = 4; + * @param index The index of the element to return. + * @return The service at the given index. + */ + public String getService(int index) { + return service_.get(index); + } + + /** + *
+         * The openAPI services. Each service is an or condition.
+         * 
+ * + * repeated string service = 4; + * @param index The index of the value to return. + * @return The bytes of the service at the given index. + */ + public com.google.protobuf.ByteString getServiceBytes(int index) { + return service_.getByteString(index); + } + + /** + *
+         * The openAPI services. Each service is an or condition.
+         * 
+ * + * repeated string service = 4; + * @param index The index to set the value at. + * @param value The service to set. + * @return This builder for chaining. + */ + public Builder setService(int index, String value) { + if (value == null) { + throw new NullPointerException(); + } + ensureServiceIsMutable(); + service_.set(index, value); + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + + /** + *
+         * The openAPI services. Each service is an or condition.
+         * 
+ * + * repeated string service = 4; + * @param value The service to add. + * @return This builder for chaining. + */ + public Builder addService(String value) { + if (value == null) { + throw new NullPointerException(); + } + ensureServiceIsMutable(); + service_.add(value); + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + + /** + *
+         * The openAPI services. Each service is an or condition.
+         * 
+ * + * repeated string service = 4; + * @param values The service to add. + * @return This builder for chaining. + */ + public Builder addAllService(Iterable values) { + ensureServiceIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll(values, service_); + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + + /** + *
+         * The openAPI services. Each service is an or condition.
+         * 
+ * + * repeated string service = 4; + * @return This builder for chaining. + */ + public Builder clearService() { + service_ = com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000008); + ; + onChanged(); + return this; + } + + /** + *
+         * The openAPI services. Each service is an or condition.
+         * 
+ * + * repeated string service = 4; + * @param value The bytes of the service to add. + * @return This builder for chaining. + */ + public Builder addServiceBytes(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + ensureServiceIsMutable(); + service_.add(value); + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + + private Object openapi_ = ""; + + /** + *
+         * The openAPI specification version, using a major.minor.patch versioning scheme
+         * e.g. 3.0.1, 3.1.0
+         * The default value is '3.0.1'.
+         * 
+ * + * string openapi = 5; + * @return The openapi. + */ + public String getOpenapi() { + Object ref = openapi_; + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + openapi_ = s; + return s; + } else { + return (String) ref; + } + } + + /** + *
+         * The openAPI specification version, using a major.minor.patch versioning scheme
+         * e.g. 3.0.1, 3.1.0
+         * The default value is '3.0.1'.
+         * 
+ * + * string openapi = 5; + * @return The bytes for openapi. + */ + public com.google.protobuf.ByteString getOpenapiBytes() { + Object ref = openapi_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref); + openapi_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + /** + *
+         * The openAPI specification version, using a major.minor.patch versioning scheme
+         * e.g. 3.0.1, 3.1.0
+         * The default value is '3.0.1'.
+         * 
+ * + * string openapi = 5; + * @param value The openapi to set. + * @return This builder for chaining. + */ + public Builder setOpenapi(String value) { + if (value == null) { + throw new NullPointerException(); + } + openapi_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + + /** + *
+         * The openAPI specification version, using a major.minor.patch versioning scheme
+         * e.g. 3.0.1, 3.1.0
+         * The default value is '3.0.1'.
+         * 
+ * + * string openapi = 5; + * @return This builder for chaining. + */ + public Builder clearOpenapi() { + openapi_ = getDefaultInstance().getOpenapi(); + bitField0_ = (bitField0_ & ~0x00000010); + onChanged(); + return this; + } + + /** + *
+         * The openAPI specification version, using a major.minor.patch versioning scheme
+         * e.g. 3.0.1, 3.1.0
+         * The default value is '3.0.1'.
+         * 
+ * + * string openapi = 5; + * @param value The bytes for openapi to set. + * @return This builder for chaining. + */ + public Builder setOpenapiBytes(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + openapi_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + + private int format_ = 0; + + /** + *
+         * The format of the response.
+         * The default value is 'JSON'.
+         * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @return Whether the format field is set. + */ + @Override + public boolean hasFormat() { + return ((bitField0_ & 0x00000020) != 0); + } + + /** + *
+         * The format of the response.
+         * The default value is 'JSON'.
+         * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @return The enum numeric value on the wire for format. + */ + @Override + public int getFormatValue() { + return format_; + } + + /** + *
+         * The format of the response.
+         * The default value is 'JSON'.
+         * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @param value The enum numeric value on the wire for format to set. + * @return This builder for chaining. + */ + public Builder setFormatValue(int value) { + format_ = value; + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + + /** + *
+         * The format of the response.
+         * The default value is 'JSON'.
+         * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @return The format. + */ + @Override + public OpenAPIFormat getFormat() { + OpenAPIFormat result = OpenAPIFormat.forNumber(format_); + return result == null ? OpenAPIFormat.UNRECOGNIZED : result; + } + + /** + *
+         * The format of the response.
+         * The default value is 'JSON'.
+         * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @param value The format to set. + * @return This builder for chaining. + */ + public Builder setFormat(OpenAPIFormat value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000020; + format_ = value.getNumber(); + onChanged(); + return this; + } + + /** + *
+         * The format of the response.
+         * The default value is 'JSON'.
+         * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @return This builder for chaining. + */ + public Builder clearFormat() { + bitField0_ = (bitField0_ & ~0x00000020); + format_ = 0; + onChanged(); + return this; + } + + private boolean pretty_; + + /** + *
+         * Whether to pretty print for json.
+         * The default value is 'false'.
+         * 
+ * + * optional bool pretty = 7; + * @return Whether the pretty field is set. + */ + @Override + public boolean hasPretty() { + return ((bitField0_ & 0x00000040) != 0); + } + + /** + *
+         * Whether to pretty print for json.
+         * The default value is 'false'.
+         * 
+ * + * optional bool pretty = 7; + * @return The pretty. + */ + @Override + public boolean getPretty() { + return pretty_; + } + + /** + *
+         * Whether to pretty print for json.
+         * The default value is 'false'.
+         * 
+ * + * optional bool pretty = 7; + * @param value The pretty to set. + * @return This builder for chaining. + */ + public Builder setPretty(boolean value) { + + pretty_ = value; + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + + /** + *
+         * Whether to pretty print for json.
+         * The default value is 'false'.
+         * 
+ * + * optional bool pretty = 7; + * @return This builder for chaining. + */ + public Builder clearPretty() { + bitField0_ = (bitField0_ & ~0x00000040); + pretty_ = false; + onChanged(); + return this; + } + + @Override + public final Builder setUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @Override + public final Builder mergeUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + // @@protoc_insertion_point(builder_scope:org.apache.dubbo.metadata.OpenAPIRequest) + } + + // @@protoc_insertion_point(class_scope:org.apache.dubbo.metadata.OpenAPIRequest) + private static final OpenAPIRequest DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new OpenAPIRequest(); + } + + public static OpenAPIRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + @Override + public OpenAPIRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @Override + public OpenAPIRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIRequestOrBuilder.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIRequestOrBuilder.java new file mode 100644 index 00000000000..00e03f260cd --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIRequestOrBuilder.java @@ -0,0 +1,228 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.metadata; + +public interface OpenAPIRequestOrBuilder + extends + // @@protoc_insertion_point(interface_extends:org.apache.dubbo.metadata.OpenAPIRequest) + com.google.protobuf.MessageOrBuilder { + + /** + *
+     * The openAPI group.
+     * 
+ * + * string group = 1; + * @return The group. + */ + String getGroup(); + + /** + *
+     * The openAPI group.
+     * 
+ * + * string group = 1; + * @return The bytes for group. + */ + com.google.protobuf.ByteString getGroupBytes(); + + /** + *
+     * The openAPI version, using a major.minor.patch versioning scheme
+     * e.g. 1.0.1
+     * 
+ * + * string version = 2; + * @return The version. + */ + String getVersion(); + + /** + *
+     * The openAPI version, using a major.minor.patch versioning scheme
+     * e.g. 1.0.1
+     * 
+ * + * string version = 2; + * @return The bytes for version. + */ + com.google.protobuf.ByteString getVersionBytes(); + + /** + *
+     * The openAPI tags. Each tag is an or condition.
+     * 
+ * + * repeated string tag = 3; + * @return A list containing the tag. + */ + java.util.List getTagList(); + + /** + *
+     * The openAPI tags. Each tag is an or condition.
+     * 
+ * + * repeated string tag = 3; + * @return The count of tag. + */ + int getTagCount(); + + /** + *
+     * The openAPI tags. Each tag is an or condition.
+     * 
+ * + * repeated string tag = 3; + * @param index The index of the element to return. + * @return The tag at the given index. + */ + String getTag(int index); + + /** + *
+     * The openAPI tags. Each tag is an or condition.
+     * 
+ * + * repeated string tag = 3; + * @param index The index of the value to return. + * @return The bytes of the tag at the given index. + */ + com.google.protobuf.ByteString getTagBytes(int index); + + /** + *
+     * The openAPI services. Each service is an or condition.
+     * 
+ * + * repeated string service = 4; + * @return A list containing the service. + */ + java.util.List getServiceList(); + + /** + *
+     * The openAPI services. Each service is an or condition.
+     * 
+ * + * repeated string service = 4; + * @return The count of service. + */ + int getServiceCount(); + + /** + *
+     * The openAPI services. Each service is an or condition.
+     * 
+ * + * repeated string service = 4; + * @param index The index of the element to return. + * @return The service at the given index. + */ + String getService(int index); + + /** + *
+     * The openAPI services. Each service is an or condition.
+     * 
+ * + * repeated string service = 4; + * @param index The index of the value to return. + * @return The bytes of the service at the given index. + */ + com.google.protobuf.ByteString getServiceBytes(int index); + + /** + *
+     * The openAPI specification version, using a major.minor.patch versioning scheme
+     * e.g. 3.0.1, 3.1.0
+     * The default value is '3.0.1'.
+     * 
+ * + * string openapi = 5; + * @return The openapi. + */ + String getOpenapi(); + + /** + *
+     * The openAPI specification version, using a major.minor.patch versioning scheme
+     * e.g. 3.0.1, 3.1.0
+     * The default value is '3.0.1'.
+     * 
+ * + * string openapi = 5; + * @return The bytes for openapi. + */ + com.google.protobuf.ByteString getOpenapiBytes(); + + /** + *
+     * The format of the response.
+     * The default value is 'JSON'.
+     * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @return Whether the format field is set. + */ + boolean hasFormat(); + + /** + *
+     * The format of the response.
+     * The default value is 'JSON'.
+     * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @return The enum numeric value on the wire for format. + */ + int getFormatValue(); + + /** + *
+     * The format of the response.
+     * The default value is 'JSON'.
+     * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @return The format. + */ + OpenAPIFormat getFormat(); + + /** + *
+     * Whether to pretty print for json.
+     * The default value is 'false'.
+     * 
+ * + * optional bool pretty = 7; + * @return Whether the pretty field is set. + */ + boolean hasPretty(); + + /** + *
+     * Whether to pretty print for json.
+     * The default value is 'false'.
+     * 
+ * + * optional bool pretty = 7; + * @return The pretty. + */ + boolean getPretty(); +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceInfoV2.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceInfoV2.java index 8da76533c0c..ca4341c6c71 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceInfoV2.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceInfoV2.java @@ -17,6 +17,10 @@ package org.apache.dubbo.metadata; /** + *
+ * Service information message.
+ * 
+ * * Protobuf type {@code org.apache.dubbo.metadata.ServiceInfoV2} */ public final class ServiceInfoV2 extends com.google.protobuf.GeneratedMessageV3 @@ -24,6 +28,7 @@ public final class ServiceInfoV2 extends com.google.protobuf.GeneratedMessageV3 // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.ServiceInfoV2) ServiceInfoV2OrBuilder { private static final long serialVersionUID = 0L; + // Use ServiceInfoV2.newBuilder() to construct. private ServiceInfoV2(com.google.protobuf.GeneratedMessageV3.Builder builder) { super(builder); @@ -68,7 +73,12 @@ protected FieldAccessorTable internalGetFieldAccessorTable() { @SuppressWarnings("serial") private volatile Object name_ = ""; + /** + *
+     * The service name.
+     * 
+ * * string name = 1; * @return The name. */ @@ -84,7 +94,12 @@ public String getName() { return s; } } + /** + *
+     * The service name.
+     * 
+ * * string name = 1; * @return The bytes for name. */ @@ -104,7 +119,12 @@ public com.google.protobuf.ByteString getNameBytes() { @SuppressWarnings("serial") private volatile Object group_ = ""; + /** + *
+     * The service group.
+     * 
+ * * string group = 2; * @return The group. */ @@ -120,7 +140,12 @@ public String getGroup() { return s; } } + /** + *
+     * The service group.
+     * 
+ * * string group = 2; * @return The bytes for group. */ @@ -140,7 +165,12 @@ public com.google.protobuf.ByteString getGroupBytes() { @SuppressWarnings("serial") private volatile Object version_ = ""; + /** + *
+     * The service version.
+     * 
+ * * string version = 3; * @return The version. */ @@ -156,7 +186,12 @@ public String getVersion() { return s; } } + /** + *
+     * The service version.
+     * 
+ * * string version = 3; * @return The bytes for version. */ @@ -176,7 +211,12 @@ public com.google.protobuf.ByteString getVersionBytes() { @SuppressWarnings("serial") private volatile Object protocol_ = ""; + /** + *
+     * The service protocol.
+     * 
+ * * string protocol = 4; * @return The protocol. */ @@ -192,7 +232,12 @@ public String getProtocol() { return s; } } + /** + *
+     * The service protocol.
+     * 
+ * * string protocol = 4; * @return The bytes for protocol. */ @@ -210,7 +255,12 @@ public com.google.protobuf.ByteString getProtocolBytes() { public static final int PORT_FIELD_NUMBER = 5; private int port_ = 0; + /** + *
+     * The service port.
+     * 
+ * * int32 port = 5; * @return The port. */ @@ -223,7 +273,12 @@ public int getPort() { @SuppressWarnings("serial") private volatile Object path_ = ""; + /** + *
+     * The service path.
+     * 
+ * * string path = 6; * @return The path. */ @@ -239,7 +294,12 @@ public String getPath() { return s; } } + /** + *
+     * The service path.
+     * 
+ * * string path = 6; * @return The bytes for path. */ @@ -281,7 +341,12 @@ private com.google.protobuf.MapField internalGetParams() { public int getParamsCount() { return internalGetParams().getMap().size(); } + /** + *
+     * A map of service parameters.
+     * 
+ * * map<string, string> params = 7; */ @Override @@ -291,6 +356,7 @@ public boolean containsParams(String key) { } return internalGetParams().getMap().containsKey(key); } + /** * Use {@link #getParamsMap()} instead. */ @@ -299,14 +365,24 @@ public boolean containsParams(String key) { public java.util.Map getParams() { return getParamsMap(); } + /** + *
+     * A map of service parameters.
+     * 
+ * * map<string, string> params = 7; */ @Override public java.util.Map getParamsMap() { return internalGetParams().getMap(); } + /** + *
+     * A map of service parameters.
+     * 
+ * * map<string, string> params = 7; */ @Override @@ -320,7 +396,12 @@ public java.util.Map getParamsMap() { java.util.Map map = internalGetParams().getMap(); return map.containsKey(key) ? map.get(key) : defaultValue; } + /** + *
+     * A map of service parameters.
+     * 
+ * * map<string, string> params = 7; */ @Override @@ -340,8 +421,12 @@ public String getParamsOrThrow(String key) { @Override public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; + if (isInitialized == 1) { + return true; + } + if (isInitialized == 0) { + return false; + } memoizedIsInitialized = 1; return true; @@ -375,7 +460,9 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io @Override public int getSerializedSize() { int size = memoizedSize; - if (size != -1) return size; + if (size != -1) { + return size; + } size = 0; if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(name_)) { @@ -420,14 +507,30 @@ public boolean equals(final Object obj) { } ServiceInfoV2 other = (ServiceInfoV2) obj; - if (!getName().equals(other.getName())) return false; - if (!getGroup().equals(other.getGroup())) return false; - if (!getVersion().equals(other.getVersion())) return false; - if (!getProtocol().equals(other.getProtocol())) return false; - if (getPort() != other.getPort()) return false; - if (!getPath().equals(other.getPath())) return false; - if (!internalGetParams().equals(other.internalGetParams())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; + if (!getName().equals(other.getName())) { + return false; + } + if (!getGroup().equals(other.getGroup())) { + return false; + } + if (!getVersion().equals(other.getVersion())) { + return false; + } + if (!getProtocol().equals(other.getProtocol())) { + return false; + } + if (getPort() != other.getPort()) { + return false; + } + if (!getPath().equals(other.getPath())) { + return false; + } + if (!internalGetParams().equals(other.internalGetParams())) { + return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) { + return false; + } return true; } @@ -543,7 +646,12 @@ protected Builder newBuilderForType(BuilderParent parent) { Builder builder = new Builder(parent); return builder; } + /** + *
+     * Service information message.
+     * 
+ * * Protobuf type {@code org.apache.dubbo.metadata.ServiceInfoV2} */ public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder @@ -657,6 +765,37 @@ private void buildPartial0(ServiceInfoV2 result) { } } + @Override + public Builder clone() { + return super.clone(); + } + + @Override + public Builder setField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + return super.setField(field, value); + } + + @Override + public Builder clearField(com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + + @Override + public Builder clearOneof(com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, int index, Object value) { + return super.setRepeatedField(field, index, value); + } + + @Override + public Builder addRepeatedField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + return super.addRepeatedField(field, value); + } + @Override public Builder mergeFrom(com.google.protobuf.Message other) { if (other instanceof ServiceInfoV2) { @@ -668,7 +807,9 @@ public Builder mergeFrom(com.google.protobuf.Message other) { } public Builder mergeFrom(ServiceInfoV2 other) { - if (other == ServiceInfoV2.getDefaultInstance()) return this; + if (other == ServiceInfoV2.getDefaultInstance()) { + return this; + } if (!other.getName().isEmpty()) { name_ = other.name_; bitField0_ |= 0x00000001; @@ -780,7 +921,12 @@ public Builder mergeFrom( private int bitField0_; private Object name_ = ""; + /** + *
+         * The service name.
+         * 
+ * * string name = 1; * @return The name. */ @@ -795,7 +941,12 @@ public String getName() { return (String) ref; } } + /** + *
+         * The service name.
+         * 
+ * * string name = 1; * @return The bytes for name. */ @@ -809,7 +960,12 @@ public com.google.protobuf.ByteString getNameBytes() { return (com.google.protobuf.ByteString) ref; } } + /** + *
+         * The service name.
+         * 
+ * * string name = 1; * @param value The name to set. * @return This builder for chaining. @@ -823,7 +979,12 @@ public Builder setName(String value) { onChanged(); return this; } + /** + *
+         * The service name.
+         * 
+ * * string name = 1; * @return This builder for chaining. */ @@ -833,7 +994,12 @@ public Builder clearName() { onChanged(); return this; } + /** + *
+         * The service name.
+         * 
+ * * string name = 1; * @param value The bytes for name to set. * @return This builder for chaining. @@ -850,7 +1016,12 @@ public Builder setNameBytes(com.google.protobuf.ByteString value) { } private Object group_ = ""; + /** + *
+         * The service group.
+         * 
+ * * string group = 2; * @return The group. */ @@ -865,7 +1036,12 @@ public String getGroup() { return (String) ref; } } + /** + *
+         * The service group.
+         * 
+ * * string group = 2; * @return The bytes for group. */ @@ -879,7 +1055,12 @@ public com.google.protobuf.ByteString getGroupBytes() { return (com.google.protobuf.ByteString) ref; } } + /** + *
+         * The service group.
+         * 
+ * * string group = 2; * @param value The group to set. * @return This builder for chaining. @@ -893,7 +1074,12 @@ public Builder setGroup(String value) { onChanged(); return this; } + /** + *
+         * The service group.
+         * 
+ * * string group = 2; * @return This builder for chaining. */ @@ -903,7 +1089,12 @@ public Builder clearGroup() { onChanged(); return this; } + /** + *
+         * The service group.
+         * 
+ * * string group = 2; * @param value The bytes for group to set. * @return This builder for chaining. @@ -920,7 +1111,12 @@ public Builder setGroupBytes(com.google.protobuf.ByteString value) { } private Object version_ = ""; + /** + *
+         * The service version.
+         * 
+ * * string version = 3; * @return The version. */ @@ -935,7 +1131,12 @@ public String getVersion() { return (String) ref; } } + /** + *
+         * The service version.
+         * 
+ * * string version = 3; * @return The bytes for version. */ @@ -949,7 +1150,12 @@ public com.google.protobuf.ByteString getVersionBytes() { return (com.google.protobuf.ByteString) ref; } } + /** + *
+         * The service version.
+         * 
+ * * string version = 3; * @param value The version to set. * @return This builder for chaining. @@ -963,7 +1169,12 @@ public Builder setVersion(String value) { onChanged(); return this; } + /** + *
+         * The service version.
+         * 
+ * * string version = 3; * @return This builder for chaining. */ @@ -973,7 +1184,12 @@ public Builder clearVersion() { onChanged(); return this; } + /** + *
+         * The service version.
+         * 
+ * * string version = 3; * @param value The bytes for version to set. * @return This builder for chaining. @@ -990,7 +1206,12 @@ public Builder setVersionBytes(com.google.protobuf.ByteString value) { } private Object protocol_ = ""; + /** + *
+         * The service protocol.
+         * 
+ * * string protocol = 4; * @return The protocol. */ @@ -1005,7 +1226,12 @@ public String getProtocol() { return (String) ref; } } + /** + *
+         * The service protocol.
+         * 
+ * * string protocol = 4; * @return The bytes for protocol. */ @@ -1019,7 +1245,12 @@ public com.google.protobuf.ByteString getProtocolBytes() { return (com.google.protobuf.ByteString) ref; } } + /** + *
+         * The service protocol.
+         * 
+ * * string protocol = 4; * @param value The protocol to set. * @return This builder for chaining. @@ -1033,7 +1264,12 @@ public Builder setProtocol(String value) { onChanged(); return this; } + /** + *
+         * The service protocol.
+         * 
+ * * string protocol = 4; * @return This builder for chaining. */ @@ -1043,7 +1279,12 @@ public Builder clearProtocol() { onChanged(); return this; } + /** + *
+         * The service protocol.
+         * 
+ * * string protocol = 4; * @param value The bytes for protocol to set. * @return This builder for chaining. @@ -1060,7 +1301,12 @@ public Builder setProtocolBytes(com.google.protobuf.ByteString value) { } private int port_; + /** + *
+         * The service port.
+         * 
+ * * int32 port = 5; * @return The port. */ @@ -1068,7 +1314,12 @@ public Builder setProtocolBytes(com.google.protobuf.ByteString value) { public int getPort() { return port_; } + /** + *
+         * The service port.
+         * 
+ * * int32 port = 5; * @param value The port to set. * @return This builder for chaining. @@ -1080,7 +1331,12 @@ public Builder setPort(int value) { onChanged(); return this; } + /** + *
+         * The service port.
+         * 
+ * * int32 port = 5; * @return This builder for chaining. */ @@ -1092,7 +1348,12 @@ public Builder clearPort() { } private Object path_ = ""; + /** + *
+         * The service path.
+         * 
+ * * string path = 6; * @return The path. */ @@ -1107,7 +1368,12 @@ public String getPath() { return (String) ref; } } + /** + *
+         * The service path.
+         * 
+ * * string path = 6; * @return The bytes for path. */ @@ -1121,7 +1387,12 @@ public com.google.protobuf.ByteString getPathBytes() { return (com.google.protobuf.ByteString) ref; } } + /** + *
+         * The service path.
+         * 
+ * * string path = 6; * @param value The path to set. * @return This builder for chaining. @@ -1135,7 +1406,12 @@ public Builder setPath(String value) { onChanged(); return this; } + /** + *
+         * The service path.
+         * 
+ * * string path = 6; * @return This builder for chaining. */ @@ -1145,7 +1421,12 @@ public Builder clearPath() { onChanged(); return this; } + /** + *
+         * The service path.
+         * 
+ * * string path = 6; * @param value The bytes for path to set. * @return This builder for chaining. @@ -1185,7 +1466,12 @@ private com.google.protobuf.MapField internalGetMutableParams() public int getParamsCount() { return internalGetParams().getMap().size(); } + /** + *
+         * A map of service parameters.
+         * 
+ * * map<string, string> params = 7; */ @Override @@ -1195,6 +1481,7 @@ public boolean containsParams(String key) { } return internalGetParams().getMap().containsKey(key); } + /** * Use {@link #getParamsMap()} instead. */ @@ -1203,14 +1490,24 @@ public boolean containsParams(String key) { public java.util.Map getParams() { return getParamsMap(); } + /** + *
+         * A map of service parameters.
+         * 
+ * * map<string, string> params = 7; */ @Override public java.util.Map getParamsMap() { return internalGetParams().getMap(); } + /** + *
+         * A map of service parameters.
+         * 
+ * * map<string, string> params = 7; */ @Override @@ -1224,7 +1521,12 @@ public java.util.Map getParamsMap() { java.util.Map map = internalGetParams().getMap(); return map.containsKey(key) ? map.get(key) : defaultValue; } + /** + *
+         * A map of service parameters.
+         * 
+ * * map<string, string> params = 7; */ @Override @@ -1244,7 +1546,12 @@ public Builder clearParams() { internalGetMutableParams().getMutableMap().clear(); return this; } + /** + *
+         * A map of service parameters.
+         * 
+ * * map<string, string> params = 7; */ public Builder removeParams(String key) { @@ -1254,6 +1561,7 @@ public Builder removeParams(String key) { internalGetMutableParams().getMutableMap().remove(key); return this; } + /** * Use alternate mutation accessors instead. */ @@ -1262,7 +1570,12 @@ public java.util.Map getMutableParams() { bitField0_ |= 0x00000040; return internalGetMutableParams().getMutableMap(); } + /** + *
+         * A map of service parameters.
+         * 
+ * * map<string, string> params = 7; */ public Builder putParams(String key, String value) { @@ -1276,7 +1589,12 @@ public Builder putParams(String key, String value) { bitField0_ |= 0x00000040; return this; } + /** + *
+         * A map of service parameters.
+         * 
+ * * map<string, string> params = 7; */ public Builder putAllParams(java.util.Map values) { diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceInfoV2OrBuilder.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceInfoV2OrBuilder.java index 6c39dd594fc..3daacf0d100 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceInfoV2OrBuilder.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceInfoV2OrBuilder.java @@ -22,84 +22,153 @@ public interface ServiceInfoV2OrBuilder com.google.protobuf.MessageOrBuilder { /** + *
+     * The service name.
+     * 
+ * * string name = 1; * @return The name. */ String getName(); + /** + *
+     * The service name.
+     * 
+ * * string name = 1; * @return The bytes for name. */ com.google.protobuf.ByteString getNameBytes(); /** + *
+     * The service group.
+     * 
+ * * string group = 2; * @return The group. */ String getGroup(); + /** + *
+     * The service group.
+     * 
+ * * string group = 2; * @return The bytes for group. */ com.google.protobuf.ByteString getGroupBytes(); /** + *
+     * The service version.
+     * 
+ * * string version = 3; * @return The version. */ String getVersion(); + /** + *
+     * The service version.
+     * 
+ * * string version = 3; * @return The bytes for version. */ com.google.protobuf.ByteString getVersionBytes(); /** + *
+     * The service protocol.
+     * 
+ * * string protocol = 4; * @return The protocol. */ String getProtocol(); + /** + *
+     * The service protocol.
+     * 
+ * * string protocol = 4; * @return The bytes for protocol. */ com.google.protobuf.ByteString getProtocolBytes(); /** + *
+     * The service port.
+     * 
+ * * int32 port = 5; * @return The port. */ int getPort(); /** + *
+     * The service path.
+     * 
+ * * string path = 6; * @return The path. */ String getPath(); + /** + *
+     * The service path.
+     * 
+ * * string path = 6; * @return The bytes for path. */ com.google.protobuf.ByteString getPathBytes(); /** + *
+     * A map of service parameters.
+     * 
+ * * map<string, string> params = 7; */ int getParamsCount(); + /** + *
+     * A map of service parameters.
+     * 
+ * * map<string, string> params = 7; */ boolean containsParams(String key); + /** * Use {@link #getParamsMap()} instead. */ @Deprecated java.util.Map getParams(); + /** + *
+     * A map of service parameters.
+     * 
+ * * map<string, string> params = 7; */ java.util.Map getParamsMap(); + /** + *
+     * A map of service parameters.
+     * 
+ * * map<string, string> params = 7; */ /* nullable */ @@ -107,7 +176,12 @@ String getParamsOrDefault( String key, /* nullable */ String defaultValue); + /** + *
+     * A map of service parameters.
+     * 
+ * * map<string, string> params = 7; */ String getParamsOrThrow(String key); diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataScopeModelInitializer.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataScopeModelInitializer.java index ce16b2b95fc..dc34aea41be 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataScopeModelInitializer.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataScopeModelInitializer.java @@ -18,20 +18,13 @@ import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; import org.apache.dubbo.rpc.model.ApplicationModel; -import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; public class MetadataScopeModelInitializer implements ScopeModelInitializer { - @Override - public void initializeFrameworkModel(FrameworkModel frameworkModel) {} @Override public void initializeApplicationModel(ApplicationModel applicationModel) { ScopeBeanFactory beanFactory = applicationModel.getBeanFactory(); beanFactory.registerBean(MetadataReportInstance.class); } - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/proto/metadata_service_v2.proto b/dubbo-metadata/dubbo-metadata-api/src/main/proto/metadata_service_v2.proto index 77c49d1021e..cffe6129f30 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/proto/metadata_service_v2.proto +++ b/dubbo-metadata/dubbo-metadata-api/src/main/proto/metadata_service_v2.proto @@ -22,26 +22,84 @@ option go_package = "dubbo.apache.org/dubbo-go/v3/metadata/triple_api;triple_api option java_package = "org.apache.dubbo.metadata"; option java_multiple_files = true; -service MetadataServiceV2{ +// Metadata service V2. +service MetadataServiceV2 { + // Retrieves metadata information. rpc GetMetadataInfo(MetadataRequest) returns (MetadataInfoV2); + + // Retrieves OpenAPI information. + rpc GetOpenAPIInfo(OpenAPIRequest) returns (OpenAPIInfo); } -message MetadataRequest{ +// Metadata request message. +message MetadataRequest { + // The revision of the metadata. string revision = 1; } -message MetadataInfoV2{ +// Metadata information message. +message MetadataInfoV2 { + // The application name. string app = 1; + // The application version. string version = 2; - map services = 3; + // A map of service information. + map services = 3; } -message ServiceInfoV2{ +// Service information message. +message ServiceInfoV2 { + // The service name. string name = 1; + // The service group. string group = 2; + // The service version. string version = 3; + // The service protocol. string protocol = 4; + // The service port. int32 port = 5; + // The service path. string path = 6; - map params = 7; + // A map of service parameters. + map params = 7; +} + +// OpenAPI request message. +message OpenAPIRequest { + // The openAPI group. + string group = 1; + // The openAPI version, using a major.minor.patch versioning scheme + // e.g. 1.0.1 + string version = 2; + // The openAPI tags. Each tag is an or condition. + repeated string tag = 3; + // The openAPI services. Each service is an or condition. + repeated string service = 4; + // The openAPI specification version, using a major.minor.patch versioning scheme + // e.g. 3.0.1, 3.1.0 + // The default value is '3.0.1'. + string openapi = 5; + // The format of the response. + // The default value is 'JSON'. + optional OpenAPIFormat format = 6; + // Whether to pretty print for json. + // The default value is 'false'. + optional bool pretty = 7; +} + +// Response format enumeration. +enum OpenAPIFormat { + // JSON format. + JSON = 0; + // YAML format. + YAML = 1; + // PROTO format. + PROTO = 2; +} + +// OpenAPI information message. +message OpenAPIInfo { + // The OpenAPI definition. + string definition = 1; } diff --git a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/MetricsScopeModelInitializer.java b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/MetricsScopeModelInitializer.java index 01e174ad0b3..b398777d06b 100644 --- a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/MetricsScopeModelInitializer.java +++ b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/MetricsScopeModelInitializer.java @@ -19,21 +19,13 @@ import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; import org.apache.dubbo.metrics.event.MetricsDispatcher; import org.apache.dubbo.rpc.model.ApplicationModel; -import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; public class MetricsScopeModelInitializer implements ScopeModelInitializer { - @Override - public void initializeFrameworkModel(FrameworkModel frameworkModel) {} - @Override public void initializeApplicationModel(ApplicationModel applicationModel) { ScopeBeanFactory beanFactory = applicationModel.getBeanFactory(); beanFactory.registerBean(MetricsDispatcher.class); } - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-plugin/dubbo-auth/pom.xml b/dubbo-plugin/dubbo-auth/pom.xml index 49c7f0fc630..c96561dd0fe 100644 --- a/dubbo-plugin/dubbo-auth/pom.xml +++ b/dubbo-plugin/dubbo-auth/pom.xml @@ -19,9 +19,9 @@ 4.0.0 org.apache.dubbo - dubbo-plugin + dubbo-parent ${revision} - ../pom.xml + ../../pom.xml dubbo-auth @@ -42,5 +42,16 @@ dubbo-rpc-api ${project.version} + + org.apache.dubbo + dubbo-test-check + ${project.parent.version} + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + diff --git a/dubbo-plugin/dubbo-auth/src/main/java/org/apache/dubbo/auth/AccessKeyAuthenticator.java b/dubbo-plugin/dubbo-auth/src/main/java/org/apache/dubbo/auth/AccessKeyAuthenticator.java index ce5d20aff98..173abe16c4b 100644 --- a/dubbo-plugin/dubbo-auth/src/main/java/org/apache/dubbo/auth/AccessKeyAuthenticator.java +++ b/dubbo-plugin/dubbo-auth/src/main/java/org/apache/dubbo/auth/AccessKeyAuthenticator.java @@ -62,7 +62,7 @@ public void authenticate(Invocation invocation, URL url) throws RpcAuthenticatio try { accessKeyPair = getAccessKeyPair(invocation, url); } catch (Exception e) { - throw new RpcAuthenticationException("Failed to authenticate , can't load the accessKeyPair", e); + throw new RpcAuthenticationException("Failed to authenticate , can't load the accessKeyPair"); } String computeSignature = getSignature(url, invocation, accessKeyPair.getSecretKey(), requestTimestamp); @@ -85,7 +85,7 @@ AccessKeyPair getAccessKeyPair(Invocation invocation, URL url) { throw new AccessKeyNotFoundException("AccessKeyId or secretAccessKey not found"); } } catch (Exception e) { - throw new RuntimeException("Can't load the AccessKeyPair from accessKeyStorage", e); + throw new RuntimeException("Can't load the AccessKeyPair from accessKeyStorage"); } return accessKeyPair; } diff --git a/dubbo-plugin/dubbo-auth/src/main/java/org/apache/dubbo/auth/filter/ProviderAuthHeaderFilter.java b/dubbo-plugin/dubbo-auth/src/main/java/org/apache/dubbo/auth/filter/ProviderAuthHeaderFilter.java index 2477e25d5b5..45364ebbeba 100644 --- a/dubbo-plugin/dubbo-auth/src/main/java/org/apache/dubbo/auth/filter/ProviderAuthHeaderFilter.java +++ b/dubbo-plugin/dubbo-auth/src/main/java/org/apache/dubbo/auth/filter/ProviderAuthHeaderFilter.java @@ -22,11 +22,9 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.rpc.HeaderFilter; import org.apache.dubbo.rpc.Invoker; -import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcInvocation; import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.support.RpcUtils; import static org.apache.dubbo.rpc.RpcException.AUTHORIZATION_EXCEPTION; @@ -49,13 +47,7 @@ public RpcInvocation invoke(Invoker invoker, RpcInvocation invocation) throws try { authenticator.authenticate(invocation, url); } catch (Exception e) { - Class serviceType = invoker.getInterface(); - throw new RpcException( - AUTHORIZATION_EXCEPTION, - "Forbid invoke remote service " + serviceType + " method " + RpcUtils.getMethodName(invocation) - + "() from consumer " - + invocation.getAttributes().get(Constants.REMOTE_ADDRESS_KEY) + " to provider " - + RpcContext.getServiceContext().getLocalHost()); + throw new RpcException(AUTHORIZATION_EXCEPTION, "No Auth."); } invocation.getAttributes().put(Constants.AUTH_SUCCESS, Boolean.TRUE); } diff --git a/dubbo-plugin/dubbo-compiler/pom.xml b/dubbo-plugin/dubbo-compiler/pom.xml index d5839152397..2f8ad351739 100644 --- a/dubbo-plugin/dubbo-compiler/pom.xml +++ b/dubbo-plugin/dubbo-compiler/pom.xml @@ -20,9 +20,9 @@ org.apache.dubbo - dubbo-plugin + dubbo-parent ${revision} - ../pom.xml + ../../pom.xml dubbo-compiler jar @@ -59,6 +59,17 @@ com.salesforce.servicelibs grpc-contrib + + org.apache.dubbo + dubbo-test-check + ${project.parent.version} + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + @@ -78,7 +89,7 @@ true - org.apache.dubbo.gen.grpc.DubboGrpcGenerator + org.apache.dubbo.gen.tri.Dubbo3TripleGenerator @@ -100,5 +111,4 @@ - diff --git a/dubbo-plugin/dubbo-compiler/src/main/java/org/apache/dubbo/gen/AbstractGenerator.java b/dubbo-plugin/dubbo-compiler/src/main/java/org/apache/dubbo/gen/AbstractGenerator.java index c434ec47fcb..7ea75cf5392 100644 --- a/dubbo-plugin/dubbo-compiler/src/main/java/org/apache/dubbo/gen/AbstractGenerator.java +++ b/dubbo-plugin/dubbo-compiler/src/main/java/org/apache/dubbo/gen/AbstractGenerator.java @@ -33,6 +33,9 @@ import com.github.mustachejava.DefaultMustacheFactory; import com.github.mustachejava.Mustache; import com.github.mustachejava.MustacheFactory; +import com.google.api.AnnotationsProto; +import com.google.api.HttpRule; +import com.google.api.HttpRule.PatternCase; import com.google.common.base.Charsets; import com.google.common.base.Preconditions; import com.google.common.base.Strings; @@ -42,6 +45,7 @@ import com.google.protobuf.DescriptorProtos.MethodDescriptorProto; import com.google.protobuf.DescriptorProtos.ServiceDescriptorProto; import com.google.protobuf.DescriptorProtos.SourceCodeInfo.Location; +import com.google.protobuf.ExtensionRegistry; import com.google.protobuf.compiler.PluginProtos; public abstract class AbstractGenerator { @@ -67,24 +71,40 @@ protected String getInterfaceTemplateFileName() { } private String getServiceJavaDocPrefix() { - return " "; + return ""; } private String getMethodJavaDocPrefix() { - return " "; + return " "; } public List generateFiles(PluginProtos.CodeGeneratorRequest request) { - final ProtoTypeMap typeMap = ProtoTypeMap.of(request.getProtoFileList()); + // 1. build ExtensionRegistry and registry + ExtensionRegistry registry = ExtensionRegistry.newInstance(); + AnnotationsProto.registerAllExtensions(registry); + // 2. compile proto file List protosToGenerate = request.getProtoFileList().stream() .filter(protoFile -> request.getFileToGenerateList().contains(protoFile.getName())) + .map(protoFile -> parseWithExtensions(protoFile, registry)) .collect(Collectors.toList()); + // 3. use compiled proto file build ProtoTypeMap + final ProtoTypeMap typeMap = ProtoTypeMap.of(protosToGenerate); + + // 4. find and generate serviceContext List services = findServices(protosToGenerate, typeMap); return generateFiles(services); } + private FileDescriptorProto parseWithExtensions(FileDescriptorProto protoFile, ExtensionRegistry registry) { + try { + return FileDescriptorProto.parseFrom(protoFile.toByteString(), registry); + } catch (Exception e) { + return protoFile; + } + } + private List findServices(List protos, ProtoTypeMap typeMap) { List contexts = new ArrayList<>(); @@ -171,6 +191,40 @@ private MethodContext buildMethodContext( methodContext.isManyOutput = methodProto.getServerStreaming(); methodContext.methodNumber = methodNumber; + // compile google.api.http option + HttpRule httpRule = parseHttpRule(methodProto); + if (httpRule != null) { + PatternCase patternCase = httpRule.getPatternCase(); + String path; + switch (patternCase) { + case GET: + path = httpRule.getGet(); + break; + case PUT: + path = httpRule.getPut(); + break; + case POST: + path = httpRule.getPost(); + break; + case DELETE: + path = httpRule.getDelete(); + break; + case PATCH: + path = httpRule.getPatch(); + break; + default: + path = ""; + break; + } + if (!path.isEmpty()) { + methodContext.httpMethod = patternCase.name(); + methodContext.path = path; + methodContext.body = httpRule.getBody(); + methodContext.hasMapping = true; + methodContext.needRequestAnnotation = !methodContext.body.isEmpty() || path.contains("{"); + } + } + Location methodLocation = locations.stream() .filter(location -> location.getPathCount() == METHOD_NUMBER_OF_PATHS && location.getPath(METHOD_NUMBER_OF_PATHS - 1) == methodNumber) @@ -197,6 +251,17 @@ private MethodContext buildMethodContext( return methodContext; } + private HttpRule parseHttpRule(MethodDescriptorProto methodProto) { + HttpRule rule = null; + // check methodProto have options + if (methodProto.hasOptions()) { + if (methodProto.getOptions().hasExtension(AnnotationsProto.http)) { + rule = methodProto.getOptions().getExtension(AnnotationsProto.http); + } + } + return rule; + } + private String lowerCaseFirst(String s) { return Character.toLowerCase(s.charAt(0)) + s.substring(1); } @@ -360,6 +425,26 @@ private static class MethodContext { public String grpcCallsMethodName; public int methodNumber; public String javaDoc; + /** + * The HTTP request method + */ + public String httpMethod; + /** + * The HTTP request path + */ + public String path; + /** + * The message field that the HTTP request body mapping to + */ + public String body; + /** + * Whether the method has HTTP mapping + */ + public boolean hasMapping; + /** + * Whether the request body parameter need @GRequest annotation + */ + public boolean needRequestAnnotation; // This method mimics the upper-casing method ogf gRPC to ensure compatibility // See https://github.com/grpc/grpc-java/blob/v1.8.0/compiler/src/java_plugin/cpp/java_generator.cpp#L58 diff --git a/dubbo-plugin/dubbo-compiler/src/main/resources/Dubbo3TripleInterfaceStub.mustache b/dubbo-plugin/dubbo-compiler/src/main/resources/Dubbo3TripleInterfaceStub.mustache index d31fed7efbe..ccc00ce0ed6 100644 --- a/dubbo-plugin/dubbo-compiler/src/main/resources/Dubbo3TripleInterfaceStub.mustache +++ b/dubbo-plugin/dubbo-compiler/src/main/resources/Dubbo3TripleInterfaceStub.mustache @@ -1,25 +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. -*/ + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ {{#packageName}} package {{packageName}}; {{/packageName}} import org.apache.dubbo.common.stream.StreamObserver; +import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.remoting.http12.rest.Mapping; +import org.apache.dubbo.rpc.stub.annotations.GRequest; import com.google.protobuf.Message; import java.util.HashMap; @@ -37,37 +40,39 @@ public interface {{interfaceClassName}} extends org.apache.dubbo.rpc.model.Dubbo String SERVICE_NAME = "{{serviceName}}"; {{/commonPackageName}} {{#unaryMethods}} + {{#javaDoc}} {{{javaDoc}}} {{/javaDoc}} - {{outputType}} {{methodName}}({{inputType}} request); - - CompletableFuture<{{outputType}}> {{methodName}}Async({{inputType}} request); - - + {{#hasMapping}} + @Mapping(method = HttpMethods.{{httpMethod}}, path = "{{path}}") + {{/hasMapping}} + {{outputType}} {{methodName}}({{#needRequestAnnotation}}@GRequest{{#body}}("{{body}}"){{/body}} {{/needRequestAnnotation}}{{inputType}} request); + CompletableFuture<{{outputType}}> {{methodName}}Async({{#needRequestAnnotation}}@GRequest {{/needRequestAnnotation}}{{inputType}} request); {{/unaryMethods}} - {{#serverStreamingMethods}} + {{#javaDoc}} {{{javaDoc}}} {{/javaDoc}} - void {{methodName}}({{inputType}} request, StreamObserver<{{outputType}}> responseObserver); + {{#hasMapping}} + @Mapping(method = HttpMethods.{{httpMethod}}, path = "{{path}}") + {{/hasMapping}} + void {{methodName}}({{#needRequestAnnotation}}@GRequest{{#body}}("{{body}}"){{/body}} {{/needRequestAnnotation}}{{inputType}} request, StreamObserver<{{outputType}}> responseObserver); {{/serverStreamingMethods}} - {{#biStreamingWithoutClientStreamMethods}} + {{#javaDoc}} {{{javaDoc}}} {{/javaDoc}} StreamObserver<{{inputType}}> {{methodName}}(StreamObserver<{{outputType}}> responseObserver); {{/biStreamingWithoutClientStreamMethods}} - - {{#clientStreamingMethods}} + {{#javaDoc}} {{{javaDoc}}} {{/javaDoc}} StreamObserver<{{inputType}}> {{methodName}}(StreamObserver<{{outputType}}> responseObserver); {{/clientStreamingMethods}} - } diff --git a/dubbo-plugin/dubbo-compiler/src/main/resources/Dubbo3TripleStub.mustache b/dubbo-plugin/dubbo-compiler/src/main/resources/Dubbo3TripleStub.mustache index 525eb8d634b..800aaf4a203 100644 --- a/dubbo-plugin/dubbo-compiler/src/main/resources/Dubbo3TripleStub.mustache +++ b/dubbo-plugin/dubbo-compiler/src/main/resources/Dubbo3TripleStub.mustache @@ -1,19 +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. -*/ + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ {{#packageName}} package {{packageName}}; @@ -30,6 +30,7 @@ import org.apache.dubbo.rpc.model.MethodDescriptor; import org.apache.dubbo.rpc.model.ServiceDescriptor; import org.apache.dubbo.rpc.model.StubMethodDescriptor; import org.apache.dubbo.rpc.model.StubServiceDescriptor; +import org.apache.dubbo.rpc.service.Destroyable; import org.apache.dubbo.rpc.stub.BiStreamMethodHandler; import org.apache.dubbo.rpc.stub.ServerStreamMethodHandler; import org.apache.dubbo.rpc.stub.StubInvocationUtil; @@ -49,25 +50,22 @@ public final class {{className}} { public static final String SERVICE_NAME = {{interfaceClassName}}.SERVICE_NAME; - private static final StubServiceDescriptor serviceDescriptor = new StubServiceDescriptor(SERVICE_NAME,{{interfaceClassName}}.class); + private static final StubServiceDescriptor serviceDescriptor = new StubServiceDescriptor(SERVICE_NAME, {{interfaceClassName}}.class); static { - org.apache.dubbo.rpc.protocol.tri.service.SchemaDescriptorRegistry.addSchemaDescriptor(SERVICE_NAME,{{outerClassName}}.getDescriptor()); + org.apache.dubbo.rpc.protocol.tri.service.SchemaDescriptorRegistry.addSchemaDescriptor(SERVICE_NAME, {{outerClassName}}.getDescriptor()); StubSuppliers.addSupplier(SERVICE_NAME, {{className}}::newStub); StubSuppliers.addSupplier({{interfaceClassName}}.JAVA_SERVICE_NAME, {{className}}::newStub); StubSuppliers.addDescriptor(SERVICE_NAME, serviceDescriptor); StubSuppliers.addDescriptor({{interfaceClassName}}.JAVA_SERVICE_NAME, serviceDescriptor); } - @SuppressWarnings("all") + @SuppressWarnings("unchecked") public static {{interfaceClassName}} newStub(Invoker invoker) { return new {{interfaceClassName}}Stub((Invoker<{{interfaceClassName}}>)invoker); } - {{#unaryMethods}} - {{#javaDoc}} - {{{javaDoc}}} - {{/javaDoc}} + private static final StubMethodDescriptor {{methodName}}Method = new StubMethodDescriptor("{{originMethodName}}", {{inputType}}.class, {{outputType}}.class, MethodDescriptor.RpcType.UNARY, obj -> ((Message) obj).toByteArray(), obj -> ((Message) obj).toByteArray(), {{inputType}}::parseFrom, @@ -83,31 +81,22 @@ public final class {{className}} { obj -> ((Message) obj).toByteArray(), obj -> ((Message) obj).toByteArray(), {{inputType}}::parseFrom, {{outputType}}::parseFrom); {{/unaryMethods}} - {{#serverStreamingMethods}} - {{#javaDoc}} - {{{javaDoc}}} - {{/javaDoc}} + private static final StubMethodDescriptor {{methodName}}Method = new StubMethodDescriptor("{{originMethodName}}", {{inputType}}.class, {{outputType}}.class, MethodDescriptor.RpcType.SERVER_STREAM, obj -> ((Message) obj).toByteArray(), obj -> ((Message) obj).toByteArray(), {{inputType}}::parseFrom, {{outputType}}::parseFrom); {{/serverStreamingMethods}} - {{#clientStreamingMethods}} - {{#javaDoc}} - {{{javaDoc}}} - {{/javaDoc}} + private static final StubMethodDescriptor {{methodName}}Method = new StubMethodDescriptor("{{originMethodName}}", {{inputType}}.class, {{outputType}}.class, MethodDescriptor.RpcType.CLIENT_STREAM, obj -> ((Message) obj).toByteArray(), obj -> ((Message) obj).toByteArray(), {{inputType}}::parseFrom, {{outputType}}::parseFrom); {{/clientStreamingMethods}} - {{#biStreamingWithoutClientStreamMethods}} - {{#javaDoc}} - {{{javaDoc}}} - {{/javaDoc}} + private static final StubMethodDescriptor {{methodName}}Method = new StubMethodDescriptor("{{originMethodName}}", {{inputType}}.class, {{outputType}}.class, MethodDescriptor.RpcType.BI_STREAM, obj -> ((Message) obj).toByteArray(), obj -> ((Message) obj).toByteArray(), {{inputType}}::parseFrom, @@ -130,17 +119,19 @@ public final class {{className}} { {{/biStreamingWithoutClientStreamMethods}} } - public static class {{interfaceClassName}}Stub implements {{interfaceClassName}}{ + public static class {{interfaceClassName}}Stub implements {{interfaceClassName}}, Destroyable { private final Invoker<{{interfaceClassName}}> invoker; public {{interfaceClassName}}Stub(Invoker<{{interfaceClassName}}> invoker) { this.invoker = invoker; } + @Override + public void $destroy() { + invoker.destroy(); + } {{#unaryMethods}} - {{#javaDoc}} - {{{javaDoc}}} - {{/javaDoc}} + @Override public {{outputType}} {{methodName}}({{inputType}} request){ return StubInvocationUtil.unaryCall(invoker, {{methodName}}Method, request); @@ -150,38 +141,26 @@ public final class {{className}} { return StubInvocationUtil.unaryCall(invoker, {{methodName}}AsyncMethod, request); } - {{#javaDoc}} - {{{javaDoc}}} - {{/javaDoc}} public void {{methodName}}({{inputType}} request, StreamObserver<{{outputType}}> responseObserver){ StubInvocationUtil.unaryCall(invoker, {{methodName}}Method , request, responseObserver); } {{/unaryMethods}} - {{#serverStreamingMethods}} - {{#javaDoc}} - {{{javaDoc}}} - {{/javaDoc}} + @Override public void {{methodName}}({{inputType}} request, StreamObserver<{{outputType}}> responseObserver){ StubInvocationUtil.serverStreamCall(invoker, {{methodName}}Method , request, responseObserver); } {{/serverStreamingMethods}} - {{#biStreamingWithoutClientStreamMethods}} - {{#javaDoc}} - {{{javaDoc}}} - {{/javaDoc}} + @Override public StreamObserver<{{inputType}}> {{methodName}}(StreamObserver<{{outputType}}> responseObserver){ return StubInvocationUtil.biOrClientStreamCall(invoker, {{methodName}}Method , responseObserver); } {{/biStreamingWithoutClientStreamMethods}} - {{#clientStreamingMethods}} - {{#javaDoc}} - {{{javaDoc}}} - {{/javaDoc}} + @Override public StreamObserver<{{inputType}}> {{methodName}}(StreamObserver<{{outputType}}> responseObserver){ return StubInvocationUtil.biOrClientStreamCall(invoker, {{methodName}}Method , responseObserver); @@ -190,7 +169,6 @@ public final class {{className}} { } public static abstract class {{interfaceClassName}}ImplBase implements {{interfaceClassName}}, ServerService<{{interfaceClassName}}> { - private BiConsumer> syncToAsync(java.util.function.Function syncFun) { return new BiConsumer>() { @Override @@ -205,19 +183,18 @@ public final class {{className}} { } }; } - {{#unaryMethods}} + @Override public CompletableFuture<{{outputType}}> {{methodName}}Async({{inputType}} request){ return CompletableFuture.completedFuture({{methodName}}(request)); } {{/unaryMethods}} - /** - * This server stream type unary method is only used for generated stub to support async unary method. - * It will not be called if you are NOT using Dubbo3 generated triple stub and DO NOT implement this method. - */ + // This server stream type unary method is only used for generated stub to support async unary method. + // It will not be called if you are NOT using Dubbo3 generated triple stub and DO NOT implement this method. {{#unaryMethods}} + public void {{methodName}}({{inputType}} request, StreamObserver<{{outputType}}> responseObserver){ {{methodName}}Async(request).whenComplete((r, t) -> { if (t != null) { @@ -235,69 +212,55 @@ public final class {{className}} { PathResolver pathResolver = url.getOrDefaultFrameworkModel() .getExtensionLoader(PathResolver.class) .getDefaultExtension(); - Map> handlers = new HashMap<>(); - + Map> handlers = new HashMap<>(); {{#methods}} pathResolver.addNativeStub( "/" + SERVICE_NAME + "/{{originMethodName}}"); pathResolver.addNativeStub( "/" + SERVICE_NAME + "/{{originMethodName}}Async"); // for compatibility pathResolver.addNativeStub( "/" + JAVA_SERVICE_NAME + "/{{originMethodName}}"); pathResolver.addNativeStub( "/" + JAVA_SERVICE_NAME + "/{{originMethodName}}Async"); - {{/methods}} - {{#unaryMethods}} BiConsumer<{{inputType}}, StreamObserver<{{outputType}}>> {{methodName}}Func = this::{{methodName}}; handlers.put({{methodName}}Method.getMethodName(), new UnaryStubMethodHandler<>({{methodName}}Func)); BiConsumer<{{inputType}}, StreamObserver<{{outputType}}>> {{methodName}}AsyncFunc = syncToAsync(this::{{methodName}}); handlers.put({{methodName}}ProxyAsyncMethod.getMethodName(), new UnaryStubMethodHandler<>({{methodName}}AsyncFunc)); {{/unaryMethods}} - {{#serverStreamingMethods}} handlers.put({{methodName}}Method.getMethodName(), new ServerStreamMethodHandler<>(this::{{methodName}})); {{/serverStreamingMethods}} - {{#clientStreamingMethods}} handlers.put({{methodName}}Method.getMethodName(), new BiStreamMethodHandler<>(this::{{methodName}})); {{/clientStreamingMethods}} - {{#biStreamingWithoutClientStreamMethods}} handlers.put({{methodName}}Method.getMethodName(), new BiStreamMethodHandler<>(this::{{methodName}})); {{/biStreamingWithoutClientStreamMethods}} return new StubInvoker<>(this, url, {{interfaceClassName}}.class, handlers); } - - {{#unaryMethods}} + @Override public {{outputType}} {{methodName}}({{inputType}} request){ throw unimplementedMethodException({{methodName}}Method); } - {{/unaryMethods}} - {{#serverStreamingMethods}} - {{#javaDoc}} - {{{javaDoc}}} - {{/javaDoc}} + @Override public void {{methodName}}({{inputType}} request, StreamObserver<{{outputType}}> responseObserver){ throw unimplementedMethodException({{methodName}}Method); } {{/serverStreamingMethods}} - {{#biStreamingWithoutClientStreamMethods}} + @Override public StreamObserver<{{inputType}}> {{methodName}}(StreamObserver<{{outputType}}> responseObserver){ throw unimplementedMethodException({{methodName}}Method); } {{/biStreamingWithoutClientStreamMethods}} - {{#clientStreamingMethods}} - {{#javaDoc}} - {{{javaDoc}}} - {{/javaDoc}} + @Override public StreamObserver<{{inputType}}> {{methodName}}(StreamObserver<{{outputType}}> responseObserver){ throw unimplementedMethodException({{methodName}}Method); @@ -313,5 +276,4 @@ public final class {{className}} { "/" + serviceDescriptor.getInterfaceName() + "/" + methodDescriptor.getMethodName())).asException(); } } - } diff --git a/dubbo-plugin/dubbo-compiler/src/main/resources/ReactorDubbo3TripleStub.mustache b/dubbo-plugin/dubbo-compiler/src/main/resources/ReactorDubbo3TripleStub.mustache index c36513f9165..16ac2a41709 100644 --- a/dubbo-plugin/dubbo-compiler/src/main/resources/ReactorDubbo3TripleStub.mustache +++ b/dubbo-plugin/dubbo-compiler/src/main/resources/ReactorDubbo3TripleStub.mustache @@ -51,10 +51,10 @@ public final class {{className}} { public static final String SERVICE_NAME = {{interfaceClassName}}.SERVICE_NAME; - private static final StubServiceDescriptor serviceDescriptor = new StubServiceDescriptor(SERVICE_NAME,{{interfaceClassName}}.class); + private static final StubServiceDescriptor serviceDescriptor = new StubServiceDescriptor(SERVICE_NAME, {{interfaceClassName}}.class); static { - org.apache.dubbo.rpc.protocol.tri.service.SchemaDescriptorRegistry.addSchemaDescriptor(SERVICE_NAME,{{outerClassName}}.getDescriptor()); + org.apache.dubbo.rpc.protocol.tri.service.SchemaDescriptorRegistry.addSchemaDescriptor(SERVICE_NAME, {{outerClassName}}.getDescriptor()); StubSuppliers.addSupplier(SERVICE_NAME, {{className}}::newStub); StubSuppliers.addSupplier({{interfaceClassName}}.JAVA_SERVICE_NAME, {{className}}::newStub); StubSuppliers.addDescriptor(SERVICE_NAME, serviceDescriptor); @@ -149,7 +149,7 @@ public final class {{className}} { PathResolver pathResolver = url.getOrDefaultFrameworkModel() .getExtensionLoader(PathResolver.class) .getDefaultExtension(); - Map> handlers = new HashMap<>(); + Map> handlers = new HashMap<>(); {{#methods}} pathResolver.addNativeStub( "/" + SERVICE_NAME + "/{{originMethodName}}"); diff --git a/dubbo-plugin/dubbo-filter-cache/pom.xml b/dubbo-plugin/dubbo-filter-cache/pom.xml index 0f1ee6f109c..5b27e2c9c64 100644 --- a/dubbo-plugin/dubbo-filter-cache/pom.xml +++ b/dubbo-plugin/dubbo-filter-cache/pom.xml @@ -19,8 +19,9 @@ 4.0.0 org.apache.dubbo - dubbo-plugin + dubbo-parent ${revision} + ../../pom.xml dubbo-filter-cache jar @@ -46,5 +47,16 @@ ${hazelcast_version} test + + org.apache.dubbo + dubbo-test-check + ${project.parent.version} + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + diff --git a/dubbo-plugin/dubbo-filter-validation/pom.xml b/dubbo-plugin/dubbo-filter-validation/pom.xml index bae8a9b8fb5..00c487a04ea 100644 --- a/dubbo-plugin/dubbo-filter-validation/pom.xml +++ b/dubbo-plugin/dubbo-filter-validation/pom.xml @@ -19,8 +19,9 @@ 4.0.0 org.apache.dubbo - dubbo-plugin + dubbo-parent ${revision} + ../../pom.xml dubbo-filter-validation jar @@ -76,5 +77,16 @@ ${jaxb_api_version} test + + org.apache.dubbo + dubbo-test-check + ${project.parent.version} + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + diff --git a/dubbo-plugin/dubbo-native/pom.xml b/dubbo-plugin/dubbo-native/pom.xml index 0bab55afc4e..3695ce2a148 100644 --- a/dubbo-plugin/dubbo-native/pom.xml +++ b/dubbo-plugin/dubbo-native/pom.xml @@ -19,9 +19,9 @@ 4.0.0 org.apache.dubbo - dubbo-plugin + dubbo-parent ${revision} - ../pom.xml + ../../pom.xml dubbo-native @@ -33,6 +33,17 @@ dubbo-common ${project.parent.version} + + org.apache.dubbo + dubbo-test-check + ${project.parent.version} + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + diff --git a/dubbo-plugin/dubbo-plugin-loom/pom.xml b/dubbo-plugin/dubbo-plugin-loom/pom.xml index 0f637ac38b8..9597b0e724b 100644 --- a/dubbo-plugin/dubbo-plugin-loom/pom.xml +++ b/dubbo-plugin/dubbo-plugin-loom/pom.xml @@ -19,9 +19,9 @@ 4.0.0 org.apache.dubbo - dubbo-plugin + dubbo-parent ${revision} - ../pom.xml + ../../pom.xml dubbo-plugin-loom diff --git a/dubbo-plugin/dubbo-qos-api/pom.xml b/dubbo-plugin/dubbo-qos-api/pom.xml index 37395a8bdc8..6c9d8ffa1b2 100644 --- a/dubbo-plugin/dubbo-qos-api/pom.xml +++ b/dubbo-plugin/dubbo-qos-api/pom.xml @@ -19,9 +19,9 @@ 4.0.0 org.apache.dubbo - dubbo-plugin + dubbo-parent ${revision} - ../pom.xml + ../../pom.xml dubbo-qos-api @@ -43,5 +43,16 @@ dubbo-common ${project.version} + + org.apache.dubbo + dubbo-test-check + ${project.parent.version} + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + diff --git a/dubbo-plugin/dubbo-qos/pom.xml b/dubbo-plugin/dubbo-qos/pom.xml index 1be8f4c0343..8b428b6f032 100644 --- a/dubbo-plugin/dubbo-qos/pom.xml +++ b/dubbo-plugin/dubbo-qos/pom.xml @@ -19,9 +19,9 @@ 4.0.0 org.apache.dubbo - dubbo-plugin + dubbo-parent ${revision} - ../pom.xml + ../../pom.xml dubbo-qos @@ -86,5 +86,16 @@ dubbo-metrics-default ${project.version} + + org.apache.dubbo + dubbo-test-check + ${project.parent.version} + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/QosScopeModelInitializer.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/QosScopeModelInitializer.java index 58125556bae..0da5c8352c3 100644 --- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/QosScopeModelInitializer.java +++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/QosScopeModelInitializer.java @@ -17,14 +17,15 @@ package org.apache.dubbo.qos; import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; +import org.apache.dubbo.qos.command.ActuatorCommandExecutor; import org.apache.dubbo.qos.command.util.SerializeCheckUtils; import org.apache.dubbo.qos.server.Server; import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; public class QosScopeModelInitializer implements ScopeModelInitializer { + @Override public void initializeFrameworkModel(FrameworkModel frameworkModel) { ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory(); @@ -33,8 +34,8 @@ public void initializeFrameworkModel(FrameworkModel frameworkModel) { } @Override - public void initializeApplicationModel(ApplicationModel applicationModel) {} - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} + public void initializeApplicationModel(ApplicationModel applicationModel) { + ScopeBeanFactory beanFactory = applicationModel.getBeanFactory(); + beanFactory.registerBean(ActuatorCommandExecutor.class); + } } diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/ActuatorCommandExecutor.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/ActuatorCommandExecutor.java new file mode 100644 index 00000000000..7073eea1245 --- /dev/null +++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/ActuatorCommandExecutor.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.dubbo.qos.command; + +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.qos.api.BaseCommand; +import org.apache.dubbo.qos.api.CommandContext; +import org.apache.dubbo.rpc.model.ApplicationModel; + +import java.util.Arrays; + +public class ActuatorCommandExecutor implements ActuatorExecutor { + private static final Logger logger = LoggerFactory.getLogger(ActuatorCommandExecutor.class); + private final ApplicationModel applicationModel; + + public ActuatorCommandExecutor(ApplicationModel applicationModel) { + this.applicationModel = applicationModel; + } + + @Override + public String execute(String commandName, String[] parameters) { + CommandContext commandContext; + + if (parameters == null || parameters.length == 0) { + commandContext = CommandContextFactory.newInstance(commandName); + commandContext.setHttp(true); + } else { + commandContext = CommandContextFactory.newInstance(commandName, parameters, true); + } + + logger.info("[Dubbo Actuator QoS] Command Process start. Command: " + commandContext.getCommandName() + + ", Args: " + Arrays.toString(commandContext.getArgs())); + + BaseCommand command; + try { + command = applicationModel + .getExtensionLoader(BaseCommand.class) + .getExtension(commandContext.getCommandName()); + return command.execute(commandContext, commandContext.getArgs()); + } catch (Throwable t) { + logger.info( + "[Dubbo Actuator QoS] Command Process Failed. Command: " + commandContext.getCommandName() + + ", Args: " + Arrays.toString(commandContext.getArgs()), + t); + throw t; + } + } +} diff --git a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/TripleService.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/ActuatorExecutor.java similarity index 86% rename from dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/TripleService.java rename to dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/ActuatorExecutor.java index 8aed07b507a..f63abf07e87 100644 --- a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/TripleService.java +++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/ActuatorExecutor.java @@ -14,8 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.demo; +package org.apache.dubbo.qos.command; -public interface TripleService { - String hello(); +public interface ActuatorExecutor { + + String execute(String command, String[] args); } diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/GetOpenAPI.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/GetOpenAPI.java new file mode 100644 index 00000000000..8482ea06b03 --- /dev/null +++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/GetOpenAPI.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.dubbo.qos.command.impl; + +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.qos.api.BaseCommand; +import org.apache.dubbo.qos.api.Cmd; +import org.apache.dubbo.qos.api.CommandContext; +import org.apache.dubbo.qos.api.PermissionLevel; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; +import org.apache.dubbo.remoting.http12.rest.OpenAPIService; +import org.apache.dubbo.rpc.model.FrameworkModel; + +@Cmd( + name = "getOpenAPI", + summary = "Get the openapi descriptor for specified services.", + example = { + "getOpenAPI", + "getOpenAPI groupA", + "getOpenAPI com.example.DemoService", + "getOpenAPI --group groupA --version 1.1.0 --tag tagA --service com.example. --openapi 3.0.0 --format yaml", + }, + requiredPermissionLevel = PermissionLevel.PRIVATE) +public class GetOpenAPI implements BaseCommand { + + private final FrameworkModel frameworkModel; + + public GetOpenAPI(FrameworkModel frameworkModel) { + this.frameworkModel = frameworkModel; + } + + @Override + public String execute(CommandContext commandContext, String[] args) { + OpenAPIService openAPIService = frameworkModel.getBean(OpenAPIService.class); + if (openAPIService == null) { + return "OpenAPI is not available"; + } + + OpenAPIRequest request = new OpenAPIRequest(); + + int len = args.length; + if (len > 0) { + if (len == 1) { + String arg0 = args[0]; + if (arg0.indexOf('.') > 0) { + request.setService(new String[] {arg0}); + } else { + request.setGroup(arg0); + } + } else { + for (int i = 0; i < len; i += 2) { + String value = args[i + 1]; + switch (StringUtils.substringAfterLast(args[i], '-')) { + case "group": + request.setGroup(value); + break; + case "version": + request.setVersion(value); + break; + case "tag": + request.setTag(StringUtils.tokenize(value)); + break; + case "service": + request.setService(StringUtils.tokenize(value)); + break; + case "openapi": + request.setOpenapi(value); + break; + case "format": + request.setFormat(value); + break; + default: + break; + } + } + } + } + + return openAPIService.getDocument(request); + } +} diff --git a/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand b/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand index a837d2b7024..9a336915e1b 100644 --- a/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand +++ b/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand @@ -38,3 +38,4 @@ getConfig=org.apache.dubbo.qos.command.impl.GetConfig getAddress=org.apache.dubbo.qos.command.impl.GetAddress gracefulShutdown=org.apache.dubbo.qos.command.impl.GracefulShutdown metrics_default=org.apache.dubbo.qos.command.impl.DefaultMetricsReporterCmd +getOpenAPI=org.apache.dubbo.qos.command.impl.GetOpenAPI diff --git a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/util/CommandHelperTest.java b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/util/CommandHelperTest.java index b2443ec9bfb..238b1421dd0 100644 --- a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/util/CommandHelperTest.java +++ b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/util/CommandHelperTest.java @@ -29,6 +29,7 @@ import org.apache.dubbo.qos.command.impl.GetAddress; import org.apache.dubbo.qos.command.impl.GetConfig; import org.apache.dubbo.qos.command.impl.GetEnabledRouterSnapshot; +import org.apache.dubbo.qos.command.impl.GetOpenAPI; import org.apache.dubbo.qos.command.impl.GetRecentRouterSnapshot; import org.apache.dubbo.qos.command.impl.GetRouterSnapshot; import org.apache.dubbo.qos.command.impl.GracefulShutdown; @@ -127,6 +128,7 @@ void testGetAllCommandClass() { expectedClasses.add(GetAddress.class); expectedClasses.add(GracefulShutdown.class); expectedClasses.add(DefaultMetricsReporterCmd.class); + expectedClasses.add(GetOpenAPI.class); assertThat(classes, containsInAnyOrder(expectedClasses.toArray(new Class[0]))); } diff --git a/dubbo-plugin/dubbo-reactive/pom.xml b/dubbo-plugin/dubbo-reactive/pom.xml index f32cbe921ed..6bd922f9f76 100644 --- a/dubbo-plugin/dubbo-reactive/pom.xml +++ b/dubbo-plugin/dubbo-reactive/pom.xml @@ -19,9 +19,9 @@ 4.0.0 org.apache.dubbo - dubbo-plugin + dubbo-parent ${revision} - ../pom.xml + ../../pom.xml dubbo-reactive @@ -45,6 +45,17 @@ io.projectreactor reactor-core + + org.apache.dubbo + dubbo-test-check + ${project.parent.version} + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + diff --git a/dubbo-plugin/dubbo-rest-jaxrs/pom.xml b/dubbo-plugin/dubbo-rest-jaxrs/pom.xml index fd967b07ecd..4f9f31e70d5 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/pom.xml +++ b/dubbo-plugin/dubbo-rest-jaxrs/pom.xml @@ -19,9 +19,9 @@ 4.0.0 org.apache.dubbo - dubbo-plugin + dubbo-parent ${revision} - ../pom.xml + ../../pom.xml dubbo-rest-jaxrs @@ -74,11 +74,27 @@ test-jar test + + com.google.protobuf + protobuf-java-util + test + org.spockframework spock-core test + + org.apache.dubbo + dubbo-test-check + ${project.parent.version} + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + @@ -102,9 +118,9 @@ rpc-rest-test - org.apache.dubbo + org.apache.dubbo.extensions dubbo-rpc-rest - 3.3.1-SNAPSHOT + 3.3.0 test diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/AbstractJaxrsArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/AbstractJaxrsArgumentResolver.java index e15ea565799..e51fbf0b3d5 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/AbstractJaxrsArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/AbstractJaxrsArgumentResolver.java @@ -26,7 +26,7 @@ public abstract class AbstractJaxrsArgumentResolver extends AbstractAnnotationBaseArgumentResolver { @Override - protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann) { - return new NamedValueMeta(ann.getValue(), Helper.isRequired(param), Helper.defaultValue(param)); + protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta anno) { + return new NamedValueMeta(anno.getValue(), Helper.isRequired(param), Helper.defaultValue(param)); } } diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanArgumentBinder.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanArgumentBinder.java index 90f0da7955b..25e97ce620a 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanArgumentBinder.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanArgumentBinder.java @@ -16,12 +16,10 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs; -import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.Pair; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; -import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestException; import org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver; @@ -29,8 +27,7 @@ import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.ConstructorMeta; -import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.FieldMeta; -import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.SetMethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.PropertyMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils; @@ -45,9 +42,8 @@ final class BeanArgumentBinder { private final Map, String>, BeanMeta> cache = CollectionUtils.newConcurrentHashMap(); private final ArgumentResolver argumentResolver; - BeanArgumentBinder(FrameworkModel frameworkModel) { - ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory(); - argumentResolver = beanFactory.getOrRegisterBean(CompositeArgumentResolver.class); + BeanArgumentBinder(CompositeArgumentResolver argumentResolver) { + this.argumentResolver = argumentResolver; } public Object bind(ParameterMeta paramMeta, HttpRequest request, HttpResponse response) { @@ -94,17 +90,10 @@ private Object resolveArgument(ParameterMeta paramMeta, HttpRequest request, Htt bean = constructor.newInstance(args); } - Set resolved = new HashSet<>(); - for (FieldMeta fieldMeta : beanMeta.getFields()) { - resolved.add(fieldMeta.getName()); - fieldMeta.setValue(bean, resolveArgument(fieldMeta, request, response)); - } - - for (SetMethodMeta methodMeta : beanMeta.getMethods()) { - if (resolved.contains(methodMeta.getName())) { - continue; + for (PropertyMeta propertyMeta : beanMeta.getProperties()) { + if (propertyMeta.canSetValue()) { + propertyMeta.setValue(bean, resolveArgument(propertyMeta, request, response)); } - methodMeta.setValue(bean, resolveArgument(methodMeta, request, response)); } return bean; diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanParamArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanParamArgumentResolver.java index 7c59ec6d592..a47a023222e 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanParamArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanParamArgumentResolver.java @@ -21,6 +21,7 @@ import org.apache.dubbo.remoting.http12.HttpResponse; import org.apache.dubbo.rpc.protocol.tri.rest.argument.AnnotationBaseArgumentResolver; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import java.lang.annotation.Annotation; @@ -33,6 +34,11 @@ public Class accept() { return Annotations.BeanParam.type(); } + @Override + public NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta annotation) { + return null; + } + @Override public Object resolve( ParameterMeta parameter, diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BodyArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BodyArgumentResolver.java index fc3640aa10d..441af4f6ef2 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BodyArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BodyArgumentResolver.java @@ -20,9 +20,11 @@ import org.apache.dubbo.common.io.StreamUtils; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.RestException; import org.apache.dubbo.rpc.protocol.tri.rest.argument.AnnotationBaseArgumentResolver; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; @@ -37,6 +39,11 @@ public Class accept() { return Annotations.Body.type(); } + @Override + public NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta annotation) { + return new NamedValueMeta().setParamType(ParamType.Body); + } + @Override public Object resolve( ParameterMeta parameter, diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/CookieParamArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/CookieParamArgumentResolver.java index 7f1b37b25a1..43fea3a89a9 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/CookieParamArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/CookieParamArgumentResolver.java @@ -21,6 +21,7 @@ import org.apache.dubbo.remoting.http12.HttpCookie; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import java.lang.annotation.Annotation; @@ -38,6 +39,11 @@ public Class accept() { return Annotations.CookieParam.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Cookie; + } + @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { return request.cookie(meta.name()); diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FallbackArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FallbackArgumentResolver.java index 07076ba08fa..11d88ddabef 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FallbackArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FallbackArgumentResolver.java @@ -20,6 +20,7 @@ import org.apache.dubbo.common.io.StreamUtils; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; import org.apache.dubbo.rpc.protocol.tri.rest.RestException; import org.apache.dubbo.rpc.protocol.tri.rest.argument.AbstractArgumentResolver; @@ -40,7 +41,8 @@ public boolean accept(ParameterMeta param) { @Override protected NamedValueMeta createNamedValueMeta(ParameterMeta param) { - return new NamedValueMeta(param.isAnnotated(Annotations.Nonnull), Helper.defaultValue(param)); + return new NamedValueMeta(null, param.isAnnotated(Annotations.Nonnull), Helper.defaultValue(param)) + .setParamType(param.isSimple() ? null : ParamType.Body); } @Override @@ -49,7 +51,7 @@ protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResp if (value != null) { return value; } - if (meta.parameterMeta().isSimple()) { + if (meta.parameter().isSimple()) { return request.parameter(meta.name()); } return null; diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FormArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FormArgumentResolver.java index 4f3678be5fa..e1fa754537b 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FormArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FormArgumentResolver.java @@ -19,19 +19,27 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.argument.AnnotationBaseArgumentResolver; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import java.lang.annotation.Annotation; @Activate(onClass = "org.jboss.resteasy.annotations.Form") public class FormArgumentResolver implements AnnotationBaseArgumentResolver { + @Override public Class accept() { return Annotations.Form.type(); } + @Override + public NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta annotation) { + return new NamedValueMeta().setParamType(ParamType.Body); + } + @Override public Object resolve( ParameterMeta parameter, diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FormParamArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FormParamArgumentResolver.java index 7ac1b2fcda0..88e972aa3d7 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FormParamArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FormParamArgumentResolver.java @@ -20,6 +20,7 @@ import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import java.lang.annotation.Annotation; @@ -35,6 +36,11 @@ public Class accept() { return Annotations.FormParam.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Form; + } + @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { return CollectionUtils.first(request.formParameterValues(getFullName(meta))); @@ -46,7 +52,7 @@ protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request } private String getFullName(NamedValueMeta meta) { - String prefix = meta.parameterMeta().getPrefix(); + String prefix = meta.parameter().getPrefix(); return prefix == null ? meta.name() : prefix + '.' + meta.name(); } } diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/HeaderParamArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/HeaderParamArgumentResolver.java index 8989c0ab062..7b406705a0f 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/HeaderParamArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/HeaderParamArgumentResolver.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import java.lang.annotation.Annotation; @@ -31,6 +32,11 @@ public Class accept() { return Annotations.HeaderParam.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Header; + } + @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { return request.header(meta.name()); @@ -43,6 +49,6 @@ protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request @Override protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { - return request.headers(); + return request.headers().asMap(); } } diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/Helper.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/Helper.java index 9abde6219ac..cc2e56e5352 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/Helper.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/Helper.java @@ -35,11 +35,11 @@ public final class Helper { private Helper() {} public static boolean isRequired(ParameterMeta parameter) { - return parameter.isAnnotated(Annotations.Nonnull); + return parameter.isHierarchyAnnotated(Annotations.Nonnull); } - public static String defaultValue(ParameterMeta annotation) { - AnnotationMeta meta = annotation.getAnnotation(Annotations.DefaultValue); + public static String defaultValue(ParameterMeta parameter) { + AnnotationMeta meta = parameter.findAnnotation(Annotations.DefaultValue); return meta == null ? null : meta.getValue(); } diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsRequestMappingResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsRequestMappingResolver.java index f9fc66768eb..e2ee07c12e9 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsRequestMappingResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsRequestMappingResolver.java @@ -17,6 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs; import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.config.nested.RestConfig; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.cors.CorsUtils; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMapping; @@ -29,15 +30,14 @@ import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit; -@Activate(onClass = "javax.ws.rs.Path") +@Activate(onClass = {"javax.ws.rs.Path", "javax.ws.rs.container.ContainerRequestContext"}) public class JaxrsRequestMappingResolver implements RequestMappingResolver { - private final FrameworkModel frameworkModel; private final RestToolKit toolKit; + private RestConfig restConfig; private CorsMeta globalCorsMeta; public JaxrsRequestMappingResolver(FrameworkModel frameworkModel) { - this.frameworkModel = frameworkModel; toolKit = new JaxrsRestToolKit(frameworkModel); } @@ -46,6 +46,11 @@ public RestToolKit getRestToolKit() { return toolKit; } + @Override + public void setRestConfig(RestConfig restConfig) { + this.restConfig = restConfig; + } + @Override public RequestMapping resolve(ServiceMeta serviceMeta) { AnnotationMeta path = serviceMeta.findAnnotation(Annotations.Path); @@ -70,7 +75,7 @@ public RequestMapping resolve(MethodMeta methodMeta) { } ServiceMeta serviceMeta = methodMeta.getServiceMeta(); if (globalCorsMeta == null) { - globalCorsMeta = CorsUtils.getGlobalCorsMeta(frameworkModel); + globalCorsMeta = CorsUtils.getGlobalCorsMeta(restConfig); } return builder(methodMeta, path, httpMethod) .name(methodMeta.getMethod().getName()) diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsRestToolKit.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsRestToolKit.java index 00c38a10096..65e82cfdcb6 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsRestToolKit.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsRestToolKit.java @@ -32,7 +32,7 @@ final class JaxrsRestToolKit extends AbstractRestToolKit { public JaxrsRestToolKit(FrameworkModel frameworkModel) { super(frameworkModel); - binder = new BeanArgumentBinder(frameworkModel); + binder = new BeanArgumentBinder(argumentResolver); paramConverterFactory = new ParamConverterFactory(); } diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/MatrixParamArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/MatrixParamArgumentResolver.java index a3f6b99bea2..e6517f6bda0 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/MatrixParamArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/MatrixParamArgumentResolver.java @@ -20,6 +20,7 @@ import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; @@ -36,6 +37,11 @@ public Class accept() { return Annotations.MatrixParam.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.MatrixVariable; + } + @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { return CollectionUtils.first(doResolveCollectionValue(meta, request)); diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/ParamConverterFactory.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/ParamConverterFactory.java index 15cf8dc36c6..f9686a3e586 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/ParamConverterFactory.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/ParamConverterFactory.java @@ -16,7 +16,6 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs; -import org.apache.dubbo.common.lang.Nullable; import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.utils.CollectionUtils; @@ -54,7 +53,6 @@ final class ParamConverterFactory { } } - @Nullable @SuppressWarnings("unchecked") public ParamConverter getParamConverter(Class type, Type genericType, Annotation[] annotations) { if (providers.isEmpty()) { diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/PathParamArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/PathParamArgumentResolver.java index 8e1fe007208..e1dcc96446a 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/PathParamArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/PathParamArgumentResolver.java @@ -20,11 +20,13 @@ import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; import org.apache.dubbo.rpc.protocol.tri.rest.RestParameterException; import org.apache.dubbo.rpc.protocol.tri.rest.argument.AnnotationBaseArgumentResolver; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; @@ -39,6 +41,11 @@ public Class accept() { return Annotations.PathParam.type(); } + @Override + public NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta annotation) { + return new NamedValueMeta(annotation.getValue(), true).setParamType(ParamType.PathVariable); + } + @Override public Object resolve( ParameterMeta parameter, diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/QueryParamArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/QueryParamArgumentResolver.java index 9b156c7da0a..67be793aadb 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/QueryParamArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/QueryParamArgumentResolver.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; @@ -32,6 +33,11 @@ public Class accept() { return Annotations.QueryParam.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Param; + } + @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { return request.parameter(meta.name()); diff --git a/dubbo-plugin/dubbo-rest-openapi/pom.xml b/dubbo-plugin/dubbo-rest-openapi/pom.xml new file mode 100644 index 00000000000..f3199369f92 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/pom.xml @@ -0,0 +1,92 @@ + + + + 4.0.0 + + org.apache.dubbo + dubbo-parent + ${revision} + ../../pom.xml + + + dubbo-rest-openapi + + + 2.2.25 + 5.18.2 + 2.2.0 + 1.0.0 + 0.15.0 + + + + + org.apache.dubbo + dubbo-rpc-triple + ${project.version} + + + + io.swagger.core.v3 + swagger-annotations + ${swagger-annotations.version} + + + org.webjars + swagger-ui + ${swagger-ui.version} + + + org.webjars + redoc + 2.1.5 + + + org.webjars + webjars-locator-lite + ${webjars-locator.version} + + + com.github.therapi + therapi-runtime-javadoc + ${therapi.version} + + + + org.spockframework + spock-core + test + + + + + + + org.codehaus.gmavenplus + gmavenplus-plugin + + + + compileTests + + + + + + + diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java new file mode 100644 index 00000000000..cc930f6def0 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.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.dubbo.rpc.protocol.tri.rest.openapi; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; + +import java.util.HashMap; +import java.util.Map; + +public abstract class AbstractContext { + + private final OpenAPI openAPI; + private final SchemaResolver schemaResolver; + private final ExtensionFactory extensionFactory; + + private Map attributes; + + AbstractContext(OpenAPI openAPI, SchemaResolver schemaResolver, ExtensionFactory extensionFactory) { + this.openAPI = openAPI; + this.schemaResolver = schemaResolver; + this.extensionFactory = extensionFactory; + } + + public final String getGroup() { + return openAPI.getGroup(); + } + + public final OpenAPI getOpenAPI() { + return openAPI; + } + + public final SchemaResolver getSchemaResolver() { + return schemaResolver; + } + + public final ExtensionFactory getExtensionFactory() { + return extensionFactory; + } + + @SuppressWarnings("unchecked") + public final T getAttribute(String name) { + return attributes == null ? null : (T) attributes.get(name); + } + + @SuppressWarnings("unchecked") + public final T removeAttribute(String name) { + return attributes == null ? null : (T) attributes.remove(name); + } + + public final void setAttribute(String name, Object value) { + if (attributes == null) { + attributes = new HashMap<>(); + } + attributes.put(name, value); + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java new file mode 100644 index 00000000000..8786e334fb8 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.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.dubbo.rpc.protocol.tri.rest.openapi; + +import org.apache.dubbo.common.config.Configuration; +import org.apache.dubbo.common.config.Environment; +import org.apache.dubbo.common.utils.Pair; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.nested.OpenAPIConfig; +import org.apache.dubbo.rpc.model.FrameworkModel; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import static org.apache.dubbo.rpc.Constants.H2_SETTINGS_OPENAPI_PREFIX; + +public final class ConfigFactory { + + private static Map CONFIG_METHODS; + + private final FrameworkModel frameworkModel; + private volatile Map configMap; + + public ConfigFactory(FrameworkModel frameworkModel) { + this.frameworkModel = frameworkModel; + } + + private static Environment getEnvironment(FrameworkModel frameworkModel) { + return frameworkModel.defaultApplication().modelEnvironment(); + } + + public OpenAPIConfig getConfig(String group) { + return getConfigMap().get(group); + } + + public OpenAPIConfig getGlobalConfig() { + return getConfigMap().get(Constants.GLOBAL_GROUP); + } + + private Map getConfigMap() { + if (configMap == null) { + synchronized (this) { + if (configMap == null) { + configMap = readConfigMap(); + } + } + } + return configMap; + } + + private Map readConfigMap() { + Map map = new HashMap<>(); + + Environment environment = getEnvironment(frameworkModel); + Configuration configuration = environment.getConfiguration(); + List> configMaps = environment.getConfigurationMaps(); + + Set allKeys = new HashSet<>(); + for (Map configMap : configMaps) { + for (String key : configMap.keySet()) { + if (key.startsWith(H2_SETTINGS_OPENAPI_PREFIX)) { + allKeys.add(key); + } + } + } + + int len = H2_SETTINGS_OPENAPI_PREFIX.length(); + Map, TreeMap> valuesMap = new HashMap<>(); + for (String fullKey : allKeys) { + if (fullKey.length() > len) { + char c = fullKey.charAt(len); + String group, key; + if (c == '.') { + group = StringUtils.EMPTY_STRING; + key = fullKey.substring(len + 1); + } else if (c == 's') { + int end = fullKey.indexOf('.', len + 1); + group = fullKey.substring(len + 1, end); + key = fullKey.substring(end + 1); + } else { + continue; + } + + int brkStart = key.lastIndexOf('['); + if (brkStart > 0) { + try { + String value = configuration.getString(fullKey); + if (StringUtils.isEmpty(value)) { + continue; + } + int index = Integer.parseInt(key.substring(brkStart + 1, key.length() - 1)); + valuesMap + .computeIfAbsent(Pair.of(group, key.substring(0, brkStart)), k -> new TreeMap<>()) + .put(index, value); + } catch (NumberFormatException ignored) { + } + continue; + } + + applyConfigValue(map, group, key, configuration.getString(fullKey)); + } + } + for (Map.Entry, TreeMap> entry : valuesMap.entrySet()) { + Pair pair = entry.getKey(); + String value = StringUtils.join(entry.getValue().values(), ","); + applyConfigValue(map, pair.getKey(), pair.getValue(), value); + } + map.computeIfAbsent(Constants.GLOBAL_GROUP, k -> new OpenAPIConfig()); + return map; + } + + private static void applyConfigValue(Map map, String group, String key, String value) { + if (value == null || value.isEmpty()) { + return; + } + + OpenAPIConfig config = map.computeIfAbsent(group, k -> new OpenAPIConfig()); + int index = key.indexOf("settings."); + if (index == 0) { + Map settings = config.getSettings(); + if (settings == null) { + config.setSettings(settings = new HashMap<>()); + } + settings.put(key.substring(9), value); + return; + } + + Map configMethods = CONFIG_METHODS; + if (configMethods == null) { + configMethods = new HashMap<>(); + for (Method method : OpenAPIConfig.class.getMethods()) { + String name = toConfigName(method); + if (name != null) { + configMethods.put(name, method); + } + } + CONFIG_METHODS = configMethods; + } + + Method method = configMethods.get(key); + if (method == null) { + return; + } + + Class valueType = method.getParameterTypes()[0]; + try { + if (valueType == String.class) { + method.invoke(config, value); + } else if (valueType == Boolean.class) { + method.invoke(config, StringUtils.toBoolean(value, false)); + } else if (valueType.isArray()) { + method.invoke(config, new Object[] {StringUtils.tokenize(value)}); + } + } catch (Throwable ignored) { + } + } + + private static String toConfigName(Method method) { + if (method.getParameterCount() != 1) { + return null; + } + String name = method.getName(); + if (!name.startsWith("set")) { + return null; + } + int len = name.length(); + StringBuilder sb = new StringBuilder(len); + for (int i = 3; i < len; i++) { + char c = name.charAt(i); + if (Character.isUpperCase(c)) { + if (i > 3) { + sb.append('-'); + } + sb.append(Character.toLowerCase(c)); + } else { + sb.append(c); + } + } + return sb.toString(); + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java new file mode 100644 index 00000000000..91dc4827d8e --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.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.dubbo.rpc.protocol.tri.rest.openapi; + +public final class Constants { + + public static final String VERSION_30 = "3.0.1"; + public static final String VERSION_31 = "3.1.0"; + + public static final String ALL_GROUP = "all"; + public static final String DEFAULT_GROUP = "default"; + public static final String GLOBAL_GROUP = ""; + + public static final String X_API_GROUP = "x-api-group"; + public static final String X_API_VERSION = "x-api-version"; + + public static final String X_JAVA_CLASS = "x-java-class"; + public static final String X_JAVA_METHOD = "x-java-method"; + public static final String X_JAVA_METHOD_DESCRIPTOR = "x-java-method-descriptor"; + + public static final String DUBBO_DEFAULT_SERVER = "Dubbo Default Server"; + public static final String REFERER = "referer"; + + private Constants() {} +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java new file mode 100644 index 00000000000..30aecbb41d7 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.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.dubbo.rpc.protocol.tri.rest.openapi; + +import org.apache.dubbo.remoting.http12.HttpRequest; +import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; + +public interface Context { + + OpenAPIRequest getRequest(); + + HttpRequest getHttpRequest(); + + HttpResponse getHttpResponse(); + + String getGroup(); + + OpenAPI getOpenAPI(); + + boolean isOpenAPI31(); + + SchemaResolver getSchemaResolver(); + + ExtensionFactory getExtensionFactory(); + + T getAttribute(String name); + + T removeAttribute(String name); + + void setAttribute(String name, Object value); +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java new file mode 100644 index 00000000000..8fb1cae80e6 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.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.dubbo.rpc.protocol.tri.rest.openapi; + +import org.apache.dubbo.common.utils.Holder; +import org.apache.dubbo.remoting.http12.HttpRequest; +import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; +import org.apache.dubbo.rpc.RpcContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; + +final class ContextImpl extends AbstractContext implements Context { + + private final OpenAPIRequest request; + + private Boolean openAPI31; + private Holder httpRequest; + private Holder httpResponse; + + ContextImpl(OpenAPI openAPI, SchemaResolver schemaResolver, ExtensionFactory extFactory, OpenAPIRequest request) { + super(openAPI, schemaResolver, extFactory); + this.request = request; + } + + @Override + public boolean isOpenAPI31() { + if (openAPI31 == null) { + String v = request.getOpenapi(); + openAPI31 = v != null && v.startsWith("3.1."); + } + return openAPI31; + } + + @Override + public OpenAPIRequest getRequest() { + return request; + } + + @Override + public HttpRequest getHttpRequest() { + Holder holder = httpRequest; + if (holder == null) { + holder = new Holder<>(); + holder.set(RpcContext.getServiceContext().getRequest(HttpRequest.class)); + httpRequest = holder; + } + return holder.get(); + } + + @Override + public HttpResponse getHttpResponse() { + Holder holder = httpResponse; + if (holder == null) { + holder = new Holder<>(); + holder.set(RpcContext.getServiceContext().getResponse(HttpResponse.class)); + httpResponse = holder; + } + return holder.get(); + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPINamingStrategy.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPINamingStrategy.java new file mode 100644 index 00000000000..a2f5c876ea0 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPINamingStrategy.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.dubbo.rpc.protocol.tri.rest.openapi; + +import org.apache.dubbo.common.io.Bytes; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils; + +import java.lang.reflect.Method; +import java.util.concurrent.ThreadLocalRandom; + +public class DefaultOpenAPINamingStrategy implements OpenAPINamingStrategy { + + @Override + public String generateOperationId(MethodMeta methodMeta, OpenAPI openAPI) { + return methodMeta.getMethod().getName(); + } + + @Override + public String resolveOperationIdConflict(int attempt, String operationId, MethodMeta methodMeta, OpenAPI openAPI) { + Method method = methodMeta.getMethod(); + if (attempt == 1) { + String sig = TypeUtils.buildSig(method); + if (sig != null) { + return method.getName() + '_' + sig; + } + } + return method.getName() + '_' + buildPostfix(attempt, method.toString()); + } + + @Override + public String generateSchemaName(Class clazz, OpenAPI openAPI) { + return clazz.getSimpleName(); + } + + @Override + public String resolveSchemaNameConflict(int attempt, String schemaName, Class clazz, OpenAPI openAPI) { + return clazz.getSimpleName() + '_' + buildPostfix(attempt, clazz.getName()); + } + + private static String buildPostfix(int attempt, String str) { + if (attempt > 4) { + str += ThreadLocalRandom.current().nextInt(10000); + } + return Bytes.bytes2hex(Bytes.getMD5(str), 0, Math.min(4, attempt)); + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java new file mode 100644 index 00000000000..a991562a957 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java @@ -0,0 +1,308 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.rpc.protocol.tri.rest.openapi; + +import org.apache.dubbo.common.logger.FluentLogger; +import org.apache.dubbo.common.logger.Level; +import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository; +import org.apache.dubbo.common.utils.LRUCache; +import org.apache.dubbo.common.utils.Pair; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.remoting.http12.HttpRequest; +import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.HttpResult; +import org.apache.dubbo.remoting.http12.exception.HttpResultPayloadException; +import org.apache.dubbo.remoting.http12.message.MediaType; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; +import org.apache.dubbo.remoting.http12.rest.OpenAPIService; +import org.apache.dubbo.rpc.RpcContext; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.ExceptionUtils; +import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RadixTree; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RadixTree.Match; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.Registration; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingRegistry; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HandlerMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.util.PathUtils; +import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; + +import java.lang.ref.SoftReference; +import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +public class DefaultOpenAPIService implements OpenAPIRequestHandler, OpenAPIService { + + private static final FluentLogger LOG = FluentLogger.of(DefaultOpenAPIService.class); + private static final String API_DOCS = "/api-docs"; + + private final LRUCache> cache = new LRUCache<>(64); + private final FrameworkModel frameworkModel; + private final ConfigFactory configFactory; + private final ExtensionFactory extensionFactory; + private final DefinitionResolver definitionResolver; + private final DefinitionMerger definitionMerger; + private final DefinitionFilter definitionFilter; + private final DefinitionEncoder definitionEncoder; + private final RadixTree tree; + + private volatile List openAPIs; + private boolean exported; + private ScheduledFuture exportFuture; + + public DefaultOpenAPIService(FrameworkModel frameworkModel) { + this.frameworkModel = frameworkModel; + configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class); + extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class); + definitionResolver = new DefinitionResolver(frameworkModel); + definitionMerger = new DefinitionMerger(frameworkModel); + definitionFilter = new DefinitionFilter(frameworkModel); + definitionEncoder = new DefinitionEncoder(frameworkModel); + tree = initRequestHandlers(); + } + + private RadixTree initRequestHandlers() { + RadixTree tree = new RadixTree<>(false); + for (OpenAPIRequestHandler handler : extensionFactory.getExtensions(OpenAPIRequestHandler.class)) { + for (String path : handler.getPaths()) { + tree.addPath(path, handler); + } + } + tree.addPath(this, API_DOCS, API_DOCS + "/{group}"); + return tree; + } + + @Override + public HttpResult handle(String path, HttpRequest httpRequest, HttpResponse httpResponse) { + OpenAPIRequest request = httpRequest.attribute(OpenAPIRequest.class.getName()); + String group = RequestUtils.getPathVariable(httpRequest, "group"); + if (group != null) { + request.setGroup(StringUtils.substringBeforeLast(group, '.')); + } + return HttpResult.builder() + .contentType(MediaType.APPLICATION + '/' + request.getFormat()) + .body(handleDocument(request, httpRequest).getBytes(StandardCharsets.UTF_8)) + .build(); + } + + @Override + public Collection getOpenAPIGroups() { + Set groups = new LinkedHashSet<>(); + groups.add(Constants.DEFAULT_GROUP); + for (OpenAPI openAPI : getOpenAPIs()) { + groups.add(openAPI.getGroup()); + openAPI.walkOperations(operation -> { + String group = operation.getGroup(); + if (StringUtils.isNotEmpty(group)) { + groups.add(group); + } + }); + } + return groups; + } + + public OpenAPI getOpenAPI(OpenAPIRequest request) { + return definitionFilter.filter(definitionMerger.merge(getOpenAPIs(), request), request); + } + + private List getOpenAPIs() { + if (openAPIs == null) { + synchronized (this) { + if (openAPIs == null) { + openAPIs = resolveOpenAPIs(); + } + } + } + return openAPIs; + } + + private List resolveOpenAPIs() { + RequestMappingRegistry registry = frameworkModel.getBean(RequestMappingRegistry.class); + if (registry == null) { + return Collections.emptyList(); + } + + Map>> byClassMap = new HashMap<>(); + for (Registration registration : registry.getRegistrations()) { + HandlerMeta meta = registration.getMeta(); + byClassMap + .computeIfAbsent(new Key(meta.getService()), k -> new IdentityHashMap<>()) + .computeIfAbsent(meta.getMethod().getMethod(), k -> new ArrayList<>(1)) + .add(registration); + } + + List openAPIs = new ArrayList<>(byClassMap.size()); + for (Map.Entry>> entry : byClassMap.entrySet()) { + OpenAPI openAPI = definitionResolver.resolve( + entry.getKey().serviceMeta, entry.getValue().values()); + if (openAPI != null) { + openAPIs.add(openAPI); + } + } + openAPIs.sort(Comparator.comparingInt(OpenAPI::getPriority)); + + return openAPIs; + } + + @Override + public String getDocument(OpenAPIRequest request) { + String path = null; + try { + request = Helper.formatRequest(request); + + HttpRequest httpRequest = RpcContext.getServiceContext().getRequest(HttpRequest.class); + if (!RequestUtils.isRestRequest(httpRequest)) { + return handleDocument(request, null); + } + + path = RequestUtils.getPathVariable(httpRequest, "path"); + if (StringUtils.isEmpty(path)) { + String url = PathUtils.join(httpRequest.path(), "swagger-ui/index.html"); + throw HttpResult.found(url).toPayload(); + } + + path = '/' + path; + List> matches = tree.matchRelaxed(path); + if (matches.isEmpty()) { + throw HttpResult.notFound().toPayload(); + } + + Collections.sort(matches); + Match match = matches.get(0); + HttpResponse httpResponse = RpcContext.getServiceContext().getResponse(HttpResponse.class); + if (request.getFormat() == null) { + request.setFormat(Helper.parseFormat(httpResponse.contentType())); + } + httpRequest.setAttribute(OpenAPIRequest.class.getName(), request); + httpRequest.setAttribute(RestConstants.URI_TEMPLATE_VARIABLES_ATTRIBUTE, match.getVariableMap()); + throw match.getValue().handle(path, httpRequest, httpResponse).toPayload(); + } catch (HttpResultPayloadException e) { + throw e; + } catch (Throwable t) { + Level level = ExceptionUtils.resolveLogLevel(ExceptionUtils.unwrap(t)); + LOG.log(level, "Failed to processing OpenAPI request {} for path: '{}'", request, path, t); + throw t; + } + } + + private String handleDocument(OpenAPIRequest request, HttpRequest httpRequest) { + if (Boolean.FALSE.equals(configFactory.getGlobalConfig().getCache())) { + return definitionEncoder.encode(getOpenAPI(request), request); + } + + StringBuilder sb = new StringBuilder(); + if (httpRequest != null) { + String host = httpRequest.serverHost(); + if (host != null) { + String referer = httpRequest.header(Constants.REFERER); + sb.append(referer != null && referer.contains(host) ? '/' : host); + } + } + sb.append('|').append(request.toString()); + + String cacheKey = sb.toString(); + SoftReference ref = cache.get(cacheKey); + if (ref != null) { + String value = ref.get(); + if (value != null) { + return value; + } + } + String value = definitionEncoder.encode(getOpenAPI(request), request); + cache.put(cacheKey, new SoftReference<>(value)); + return value; + } + + @Override + public void refresh() { + LOG.debug("Refreshing OpenAPI documents"); + openAPIs = null; + cache.clear(); + if (exported) { + export(); + } + } + + @Override + public void export() { + if (!extensionFactory.hasExtensions(OpenAPIDocumentPublisher.class)) { + return; + } + + try { + if (exportFuture != null) { + exportFuture.cancel(false); + } + exportFuture = frameworkModel + .getBean(FrameworkExecutorRepository.class) + .getMetadataRetryExecutor() + .schedule(this::doExport, 30, TimeUnit.SECONDS); + exported = true; + } catch (Throwable t) { + LOG.internalWarn("Failed to export OpenAPI documents", t); + } + } + + private void doExport() { + for (OpenAPIDocumentPublisher publisher : extensionFactory.getExtensions(OpenAPIDocumentPublisher.class)) { + try { + publisher.publish(request -> { + OpenAPI openAPI = getOpenAPI(request); + String document = definitionEncoder.encode(openAPI, request); + return Pair.of(openAPI, document); + }); + } catch (Throwable t) { + LOG.internalWarn("Failed to publish OpenAPI document by {}", publisher, t); + } + } + exportFuture = null; + } + + private static final class Key { + + private final ServiceMeta serviceMeta; + + public Key(ServiceMeta serviceMeta) { + this.serviceMeta = serviceMeta; + } + + @SuppressWarnings({"EqualsWhichDoesntCheckParameterClass", "EqualsDoesntCheckParameterClass"}) + @Override + public boolean equals(Object obj) { + return serviceMeta.getType() == ((Key) obj).serviceMeta.getType(); + } + + @Override + public int hashCode() { + return serviceMeta.getType().hashCode(); + } + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java new file mode 100644 index 00000000000..6ae84c5cf6b --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.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.dubbo.rpc.protocol.tri.rest.openapi; + +import org.apache.dubbo.common.utils.JsonUtils; +import org.apache.dubbo.remoting.http12.exception.UnsupportedMediaTypeException; +import org.apache.dubbo.remoting.http12.message.MediaType; +import org.apache.dubbo.remoting.http12.message.codec.YamlCodec; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; + +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; +import java.util.LinkedHashMap; +import java.util.Map; + +final class DefinitionEncoder { + + private final ExtensionFactory extensionFactory; + private final SchemaResolver schemaResolver; + + private ProtoEncoder protoEncoder; + + DefinitionEncoder(FrameworkModel frameworkModel) { + extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class); + schemaResolver = frameworkModel.getOrRegisterBean(SchemaResolver.class); + } + + public String encode(OpenAPI openAPI, OpenAPIRequest request) { + if (openAPI == null) { + openAPI = new OpenAPI(); + } + Map root = new LinkedHashMap<>(); + ContextImpl context = new ContextImpl(openAPI, schemaResolver, extensionFactory, request); + openAPI.writeTo(root, context); + + String format = request.getFormat(); + format = format == null ? MediaType.JSON : format.toLowerCase(); + switch (format) { + case MediaType.JSON: + if (Boolean.TRUE.equals(request.getPretty())) { + return JsonUtils.toPrettyJson(root); + } + return JsonUtils.toJson(root); + case "yml": + case "yaml": + ByteArrayOutputStream os = new ByteArrayOutputStream(4096); + YamlCodec.INSTANCE.encode(os, root, StandardCharsets.UTF_8); + return new String(os.toByteArray(), StandardCharsets.UTF_8); + case "proto": + if (protoEncoder == null) { + protoEncoder = new ProtoEncoder(); + } + return protoEncoder.encode(openAPI); + default: + throw new UnsupportedMediaTypeException("text/" + format); + } + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java new file mode 100644 index 00000000000..2c6b037c6c6 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java @@ -0,0 +1,410 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.rpc.protocol.tri.rest.openapi; + +import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.remoting.http12.HttpRequest; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ApiResponse; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Components; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Header; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.MediaType; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Node; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.RequestBody; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.SecurityScheme; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Server; + +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.function.Consumer; +import java.util.function.Supplier; + +final class DefinitionFilter { + + private final ExtensionFactory extensionFactory; + private final SchemaResolver schemaResolver; + + public DefinitionFilter(FrameworkModel frameworkModel) { + extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class); + schemaResolver = frameworkModel.getOrRegisterBean(SchemaResolver.class); + } + + public OpenAPI filter(OpenAPI openAPI, OpenAPIRequest request) { + OpenAPIFilter[] filters = extensionFactory.getExtensions(OpenAPIFilter.class, request.getGroup()); + Context context = new ContextImpl(openAPI, schemaResolver, extensionFactory, request); + + if (filters.length > 0) { + for (OpenAPIFilter filter : filters) { + openAPI = filter.filterOpenAPI(openAPI, context); + if (openAPI == null) { + return null; + } + } + + filterPaths(openAPI, filters, context); + + filterComponents(openAPI, filters, context); + + for (OpenAPIFilter filter : filters) { + openAPI = filter.filterOpenAPICompletion(openAPI, context); + if (openAPI == null) { + return null; + } + } + } + + filterServer(openAPI, context); + + return openAPI; + } + + private static void filterServer(OpenAPI openAPI, Context context) { + List servers = openAPI.getServers(); + if (servers == null || servers.size() != 1) { + return; + } + Server server = servers.get(0); + if (!Constants.DUBBO_DEFAULT_SERVER.equals(server.getDescription())) { + return; + } + HttpRequest httpRequest = context.getHttpRequest(); + if (httpRequest == null) { + return; + } + String host = httpRequest.serverHost(); + if (host == null) { + return; + } + String referer = httpRequest.header(Constants.REFERER); + if (referer != null && referer.contains(host)) { + servers.clear(); + } else { + server.setUrl(httpRequest.scheme() + "://" + host); + } + } + + private void filterPaths(OpenAPI openAPI, OpenAPIFilter[] filters, Context context) { + Map paths = openAPI.getPaths(); + if (paths == null) { + return; + } + + Iterator> it = paths.entrySet().iterator(); + out: + while (it.hasNext()) { + Entry entry = it.next(); + PathItem pathItem = entry.getValue(); + PathItem initialPathItem = pathItem; + for (OpenAPIFilter filter : filters) { + pathItem = filter.filterPathItem(entry.getKey(), pathItem, context); + if (pathItem == null) { + it.remove(); + continue out; + } + } + if (pathItem != initialPathItem) { + entry.setValue(pathItem); + } + + filterOperation(pathItem, filters, context); + } + } + + private void filterOperation(PathItem pathItem, OpenAPIFilter[] filters, Context context) { + Map operations = pathItem.getOperations(); + if (operations == null) { + return; + } + + Iterator> it = operations.entrySet().iterator(); + out: + while (it.hasNext()) { + Entry entry = it.next(); + HttpMethods httpMethod = entry.getKey(); + Operation operation = entry.getValue(); + Operation initialOperation = operation; + for (OpenAPIFilter filter : filters) { + operation = filter.filterOperation(httpMethod, operation, pathItem, context); + if (operation == null) { + it.remove(); + continue out; + } + } + if (operation != initialOperation) { + entry.setValue(operation); + } + + filterParameter(operation, filters, context); + filterRequestBody(operation, filters, context); + filterResponse(operation, filters, context); + } + } + + private void filterParameter(Operation operation, OpenAPIFilter[] filters, Context context) { + List parameters = operation.getParameters(); + if (parameters == null) { + return; + } + + ListIterator it = parameters.listIterator(); + out: + while (it.hasNext()) { + Parameter parameter = it.next(); + Parameter initialParameter = parameter; + for (OpenAPIFilter filter : filters) { + parameter = filter.filterParameter(parameter, operation, context); + if (parameter == null) { + it.remove(); + continue out; + } + } + if (parameter != initialParameter) { + it.set(parameter); + } + + filterContext(parameter.getContents(), filters, context); + } + } + + private void filterRequestBody(Operation operation, OpenAPIFilter[] filters, Context context) { + RequestBody body = operation.getRequestBody(); + if (body == null) { + return; + } + + RequestBody initialRequestBody = body; + for (OpenAPIFilter filter : filters) { + body = filter.filterRequestBody(body, operation, context); + if (body == null) { + operation.setRequestBody(null); + return; + } + } + if (body != initialRequestBody) { + operation.setRequestBody(body); + } + + filterContext(body.getContents(), filters, context); + } + + private void filterResponse(Operation operation, OpenAPIFilter[] filters, Context context) { + Map responses = operation.getResponses(); + if (responses == null) { + return; + } + + Iterator> it = responses.entrySet().iterator(); + out: + while (it.hasNext()) { + Entry entry = it.next(); + ApiResponse response = entry.getValue(); + ApiResponse initialApiResponse = response; + for (OpenAPIFilter filter : filters) { + response = filter.filterResponse(response, operation, context); + if (response == null) { + it.remove(); + continue out; + } + } + if (response != initialApiResponse) { + entry.setValue(response); + } + + filterHeader(response, operation, filters, context); + filterContext(response.getContents(), filters, context); + } + } + + private void filterHeader(ApiResponse response, Operation operation, OpenAPIFilter[] filters, Context context) { + Map headers = response.getHeaders(); + if (headers == null) { + return; + } + + Iterator> it = headers.entrySet().iterator(); + out: + while (it.hasNext()) { + Entry entry = it.next(); + Header header = entry.getValue(); + Header initialHeader = header; + for (OpenAPIFilter filter : filters) { + header = filter.filterHeader(header, response, operation, context); + if (header == null) { + it.remove(); + continue out; + } + } + if (header != initialHeader) { + entry.setValue(header); + } + + filterSchema(header::getSchema, header::setSchema, header, filters, context); + + Map contents = header.getContents(); + if (contents == null) { + continue; + } + + for (MediaType content : contents.values()) { + filterSchema(content::getSchema, content::setSchema, content, filters, context); + } + } + } + + private boolean filterContext(Map contents, OpenAPIFilter[] filters, Context context) { + if (contents == null) { + return true; + } + + for (MediaType content : contents.values()) { + filterSchema(content::getSchema, content::setSchema, content, filters, context); + } + return false; + } + + private void filterComponents(OpenAPI openAPI, OpenAPIFilter[] filters, Context context) { + Components components = openAPI.getComponents(); + if (components == null) { + return; + } + + filterSchemas(components, filters, context); + filterSecuritySchemes(components, filters, context); + } + + private void filterSchemas(Components components, OpenAPIFilter[] filters, Context context) { + if (components == null) { + return; + } + + Map schemas = components.getSchemas(); + if (schemas == null) { + return; + } + + for (Entry entry : schemas.entrySet()) { + filterSchema(entry::getValue, entry::setValue, components, filters, context); + } + } + + private void filterSchema( + Supplier getter, Consumer setter, Node owner, OpenAPIFilter[] filters, Context context) { + Schema schema = getter.get(); + if (schema == null) { + return; + } + + Schema initialSchema = schema; + for (OpenAPIFilter filter : filters) { + schema = filter.filterSchema(schema, owner, context); + if (schema == null) { + setter.accept(null); + return; + } + } + if (schema != initialSchema) { + setter.accept(schema); + } + + filterSchema(schema::getItems, schema::setItems, schema, filters, context); + + Map properties = schema.getProperties(); + if (properties != null) { + out: + for (Entry entry : properties.entrySet()) { + String name = entry.getKey(); + Schema valueSchema = entry.getValue(); + for (OpenAPIFilter filter : filters) { + valueSchema = filter.filterSchemaProperty(name, valueSchema, schema, context); + if (valueSchema == null) { + entry.setValue(null); + continue out; + } + } + + filterSchema(entry::getValue, entry::setValue, schema, filters, context); + } + } + + filterSchema( + schema::getAdditionalPropertiesSchema, schema::setAdditionalPropertiesSchema, schema, filters, context); + + List allOf = schema.getAllOf(); + if (allOf != null) { + ListIterator it = allOf.listIterator(); + while (it.hasNext()) { + filterSchema(it::next, it::set, schema, filters, context); + } + } + + List oneOf = schema.getOneOf(); + if (oneOf != null) { + ListIterator it = oneOf.listIterator(); + while (it.hasNext()) { + filterSchema(it::next, it::set, schema, filters, context); + } + } + + List anyOf = schema.getAnyOf(); + if (anyOf != null) { + ListIterator it = anyOf.listIterator(); + while (it.hasNext()) { + filterSchema(it::next, it::set, schema, filters, context); + } + } + + filterSchema(schema::getNot, schema::setNot, schema, filters, context); + } + + private void filterSecuritySchemes(Components components, OpenAPIFilter[] filters, Context context) { + if (components == null) { + return; + } + + Map securitySchemes = components.getSecuritySchemes(); + if (securitySchemes == null) { + return; + } + + Iterator> it = securitySchemes.entrySet().iterator(); + out: + while (it.hasNext()) { + Entry entry = it.next(); + SecurityScheme securityScheme = entry.getValue(); + SecurityScheme initialSecurityScheme = securityScheme; + for (OpenAPIFilter filter : filters) { + securityScheme = filter.filterSecurityScheme(securityScheme, context); + if (securityScheme == null) { + it.remove(); + continue out; + } + } + if (securityScheme != initialSecurityScheme) { + entry.setValue(securityScheme); + } + } + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java new file mode 100644 index 00000000000..68206ae6468 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java @@ -0,0 +1,642 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.rpc.protocol.tri.rest.openapi; + +import org.apache.dubbo.common.logger.FluentLogger; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.common.utils.JsonUtils; +import org.apache.dubbo.config.nested.OpenAPIConfig; +import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ApiResponse; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Components; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Contact; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ExternalDocs; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Header; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Info; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.License; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.MediaType; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Node; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.RequestBody; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.SecurityRequirement; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.SecurityScheme; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Server; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Tag; + +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import java.util.TreeMap; +import java.util.stream.Collectors; + +import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.setValue; + +final class DefinitionMerger { + + private static final FluentLogger LOG = FluentLogger.of(DefinitionMerger.class); + private static final String NAMING_STRATEGY_PREFIX = "naming-strategy-"; + private static final String NAMING_STRATEGY_DEFAULT = "default"; + private static Type SECURITY_SCHEMES_TYPE; + private static Type SECURITY_TYPE; + + private final ExtensionFactory extensionFactory; + private final ConfigFactory configFactory; + private OpenAPINamingStrategy openAPINamingStrategy; + + DefinitionMerger(FrameworkModel frameworkModel) { + extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class); + configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class); + } + + private OpenAPINamingStrategy getNamingStrategy() { + if (openAPINamingStrategy == null) { + String strategy = configFactory.getGlobalConfig().getNameStrategy(); + String name = NAMING_STRATEGY_PREFIX + (strategy == null ? NAMING_STRATEGY_DEFAULT : strategy); + openAPINamingStrategy = extensionFactory.getExtension(OpenAPINamingStrategy.class, name); + Objects.requireNonNull(openAPINamingStrategy, "Can't find OpenAPINamingStrategy with name: " + name); + } + return openAPINamingStrategy; + } + + public OpenAPI merge(List openAPIs, OpenAPIRequest request) { + Info info = new Info(); + OpenAPI target = new OpenAPI().setInfo(info); + + OpenAPIConfig globalConfig = configFactory.getGlobalConfig(); + target.setGlobalConfig(globalConfig); + applyConfig(target, globalConfig); + if (openAPIs.isEmpty()) { + return target; + } + + String group = request.getGroup(); + if (group == null) { + group = Constants.DEFAULT_GROUP; + } + target.setGroup(group); + + String version = request.getVersion(); + if (version != null) { + info.setVersion(version); + } + target.setOpenapi(Helper.formatSpecVersion(request.getOpenapi())); + + OpenAPIConfig config = configFactory.getConfig(group); + target.setConfig(config); + + String[] tags = request.getTag(); + String[] services = request.getService(); + for (int i = openAPIs.size() - 1; i >= 0; i--) { + OpenAPI source = openAPIs.get(i); + if (isServiceNotMatch(source.getMeta().getServiceInterface(), services)) { + continue; + } + + if (group.equals(source.getGroup())) { + mergeBasic(target, source); + } + + mergePaths(target, source, group, version, tags); + + mergeSecuritySchemes(target, source); + + mergeTags(target, source); + } + + applyConfig(target, config); + + addSchemas(target, version, group); + + completeOperations(target); + + completeModel(target); + + return target; + } + + private void applyConfig(OpenAPI target, OpenAPIConfig config) { + if (config == null) { + return; + } + + Info info = target.getInfo(); + setValue(config::getInfoTitle, info::setTitle); + setValue(config::getInfoDescription, info::setDescription); + setValue(config::getInfoVersion, info::setVersion); + + Contact contact = info.getContact(); + if (contact == null) { + info.setContact(contact = new Contact()); + } + setValue(config::getInfoContactName, contact::setName); + setValue(config::getInfoContactUrl, contact::setUrl); + setValue(config::getInfoContactEmail, contact::setEmail); + + ExternalDocs externalDocs = target.getExternalDocs(); + if (externalDocs == null) { + target.setExternalDocs(externalDocs = new ExternalDocs()); + } + setValue(config::getExternalDocsDescription, externalDocs::setDescription); + setValue(config::getExternalDocsUrl, externalDocs::setUrl); + + String[] servers = config.getServers(); + if (servers != null) { + target.setServers(Arrays.stream(servers).map(Helper::parseServer).collect(Collectors.toList())); + } + + Components components = target.getComponents(); + if (target.getComponents() == null) { + target.setComponents(components = new Components()); + } + + String securityScheme = config.getSecurityScheme(); + if (securityScheme != null) { + try { + if (SECURITY_SCHEMES_TYPE == null) { + SECURITY_SCHEMES_TYPE = + Components.class.getDeclaredField("securitySchemes").getGenericType(); + } + components.setSecuritySchemes(JsonUtils.toJavaObject(securityScheme, SECURITY_SCHEMES_TYPE)); + } catch (NoSuchFieldException ignored) { + } + } + + String security = config.getSecurity(); + if (security != null) { + try { + if (SECURITY_TYPE == null) { + SECURITY_TYPE = OpenAPI.class.getDeclaredField("security").getGenericType(); + } + target.setSecurity(JsonUtils.toJavaObject(securityScheme, SECURITY_TYPE)); + } catch (NoSuchFieldException ignored) { + } + } + } + + private void mergeBasic(OpenAPI target, OpenAPI source) { + mergeInfo(target, source); + + if (target.getServers() == null) { + target.setServers(Node.clone(source.getServers())); + } + + List sourceSecurity = source.getSecurity(); + if (target.getSecurity() == null) { + target.setSecurity(Node.clone(sourceSecurity)); + } + + ExternalDocs sourceExternalDocs = source.getExternalDocs(); + if (sourceExternalDocs != null) { + ExternalDocs targetExternalDocs = target.getExternalDocs(); + setValue(sourceExternalDocs::getDescription, targetExternalDocs::setDescription); + setValue(sourceExternalDocs::getUrl, targetExternalDocs::setUrl); + targetExternalDocs.addExtensions(sourceExternalDocs.getExtensions()); + } + + target.addExtensions(source.getExtensions()); + } + + private void mergeInfo(OpenAPI target, OpenAPI source) { + Info sourceInfo = source.getInfo(); + if (sourceInfo == null) { + return; + } + + Info info = target.getInfo(); + setValue(sourceInfo::getTitle, info::setTitle); + setValue(sourceInfo::getSummary, info::setSummary); + setValue(sourceInfo::getDescription, info::setDescription); + setValue(sourceInfo::getTermsOfService, info::setTermsOfService); + setValue(sourceInfo::getVersion, info::setVersion); + + Contact sourceContact = sourceInfo.getContact(); + if (sourceContact != null) { + Contact contact = info.getContact(); + setValue(sourceContact::getName, contact::setName); + setValue(sourceContact::getUrl, contact::setUrl); + setValue(sourceContact::getEmail, contact::setEmail); + + contact.addExtensions(sourceContact.getExtensions()); + } + + License sourceLicense = sourceInfo.getLicense(); + if (sourceLicense != null) { + License license = info.getLicense(); + if (license == null) { + info.setLicense(license = new License()); + } + setValue(sourceLicense::getName, license::setName); + setValue(sourceLicense::getUrl, license::setUrl); + license.addExtensions(sourceLicense.getExtensions()); + } + + info.addExtensions(sourceInfo.getExtensions()); + } + + private void mergePaths(OpenAPI target, OpenAPI source, String group, String version, String[] tags) { + Map sourcePaths = source.getPaths(); + if (sourcePaths == null) { + return; + } + + Map paths = target.getPaths(); + if (paths == null) { + target.setPaths(paths = new TreeMap<>()); + } + + for (Entry entry : sourcePaths.entrySet()) { + String path = entry.getKey(); + PathItem sourcePathItem = entry.getValue(); + PathItem pathItem = paths.get(path); + if (pathItem != null) { + String ref = sourcePathItem.getRef(); + if (ref != null) { + pathItem = paths.get(ref); + } + } + if (pathItem == null) { + paths.put(path, pathItem = new PathItem()); + } + mergePath(path, pathItem, sourcePathItem, group, version, tags); + } + } + + private void mergePath(String path, PathItem target, PathItem source, String group, String version, String[] tags) { + if (target.getRef() == null) { + target.setRef(source.getRef()); + } + if (target.getSummary() == null) { + target.setSummary(source.getSummary()); + } + if (target.getDescription() == null) { + target.setDescription(source.getDescription()); + } + + Map sourceOperations = source.getOperations(); + if (sourceOperations != null) { + for (Entry entry : sourceOperations.entrySet()) { + HttpMethods httpMethod = entry.getKey(); + Operation sourceOperation = entry.getValue(); + if (isGroupNotMatch(group, sourceOperation.getGroup()) + || isVersionNotMatch(version, sourceOperation.getVersion()) + || isTagNotMatch(tags, sourceOperation.getTags())) { + continue; + } + + Operation operation = target.getOperation(httpMethod); + if (operation == null) { + target.addOperation(httpMethod, sourceOperation.clone()); + } else if (operation.getMeta() != null) { + LOG.internalWarn( + "Operation already exists, path='{}', httpMethod='{}', method={}", + path, + httpMethod, + sourceOperation.getMeta()); + } + } + } + + if (target.getServers() == null) { + List sourceServers = source.getServers(); + if (sourceServers != null) { + target.setServers(Node.clone(sourceServers)); + } + } + + List sourceParameters = source.getParameters(); + if (sourceParameters != null) { + if (target.getParameters() == null) { + target.setParameters(Node.clone(sourceParameters)); + } else { + for (Parameter parameter : sourceParameters) { + target.addParameter(parameter.clone()); + } + } + } + + target.addExtensions(source.getExtensions()); + } + + private static boolean isServiceNotMatch(String apiService, String[] services) { + if (apiService == null || services == null) { + return false; + } + for (String service : services) { + if (apiService.regionMatches(true, 0, service, 0, service.length())) { + return false; + } + } + return true; + } + + private static boolean isGroupNotMatch(String group, String sourceGroup) { + return !(sourceGroup == null && Constants.DEFAULT_GROUP.equals(group) + || Constants.ALL_GROUP.equals(group) + || group.equals(sourceGroup)); + } + + private static boolean isVersionNotMatch(String version, String sourceVersion) { + return !(version == null || sourceVersion == null || Helper.isVersionGreaterOrEqual(sourceVersion, version)); + } + + private static boolean isTagNotMatch(String[] tags, Set operationTags) { + if (tags == null || operationTags == null) { + return false; + } + for (String tag : tags) { + if (operationTags.contains(tag)) { + return false; + } + } + return true; + } + + private void mergeSecuritySchemes(OpenAPI target, OpenAPI source) { + Components sourceComponents = source.getComponents(); + if (sourceComponents == null) { + return; + } + + Map sourceSecuritySchemes = sourceComponents.getSecuritySchemes(); + if (sourceSecuritySchemes == null) { + return; + } + + Components components = target.getComponents(); + Map securitySchemes = components.getSecuritySchemes(); + if (securitySchemes == null) { + components.setSecuritySchemes(Node.clone(sourceSecuritySchemes)); + } else { + for (Entry entry : sourceSecuritySchemes.entrySet()) { + securitySchemes.computeIfAbsent( + entry.getKey(), k -> entry.getValue().clone()); + } + } + } + + private void mergeTags(OpenAPI target, OpenAPI source) { + List sourceTags = source.getTags(); + if (sourceTags == null) { + return; + } + + if (target.getTags() == null) { + target.setTags(Node.clone(sourceTags)); + } else { + for (Tag tag : sourceTags) { + target.addTag(tag.clone()); + } + } + } + + private void addSchemas(OpenAPI target, String version, String group) { + Map paths = target.getPaths(); + if (paths == null) { + return; + } + Map schemas = new IdentityHashMap<>(); + for (PathItem pathItem : paths.values()) { + Map operations = pathItem.getOperations(); + if (operations == null) { + continue; + } + for (Operation operation : operations.values()) { + List parameters = operation.getParameters(); + if (parameters != null) { + for (Parameter parameter : parameters) { + addSchema(parameter.getSchema(), schemas, group, version); + Map contents = parameter.getContents(); + if (contents == null) { + continue; + } + for (MediaType content : contents.values()) { + addSchema(content.getSchema(), schemas, group, version); + } + } + } + RequestBody requestBody = operation.getRequestBody(); + if (requestBody != null) { + Map contents = requestBody.getContents(); + if (contents == null) { + continue; + } + for (MediaType content : contents.values()) { + addSchema(content.getSchema(), schemas, group, version); + } + } + Map responses = operation.getResponses(); + if (responses != null) { + for (ApiResponse response : responses.values()) { + Map headers = response.getHeaders(); + if (headers != null) { + for (Header header : headers.values()) { + addSchema(header.getSchema(), schemas, group, version); + } + } + + Map contents = response.getContents(); + if (contents == null) { + continue; + } + for (MediaType content : contents.values()) { + addSchema(content.getSchema(), schemas, group, version); + } + } + } + } + } + + Components components = target.getComponents(); + if (components == null) { + target.setComponents(components = new Components()); + } + + Set names = CollectionUtils.newHashSet(schemas.size()); + for (Schema schema : schemas.keySet()) { + String name = schema.getName(); + if (name != null) { + names.add(name); + } + } + + OpenAPINamingStrategy strategy = getNamingStrategy(); + for (Schema schema : schemas.values()) { + String name = schema.getName(); + if (name == null) { + Class clazz = schema.getJavaType(); + name = strategy.generateSchemaName(clazz, target); + for (int i = 1; i < 100; i++) { + if (names.contains(name)) { + name = strategy.resolveSchemaNameConflict(i, name, clazz, target); + } else { + names.add(name); + break; + } + } + schema.setName(name); + } + + for (Schema sourceSchema : schema.getSourceSchemas()) { + sourceSchema.setTargetSchema(schema); + sourceSchema.setRef("#/components/schemas/" + name); + } + schema.setSourceSchemas(null); + components.addSchema(name, schema); + } + } + + private void addSchema(Schema schema, Map schemas, String group, String version) { + if (schema == null) { + return; + } + + addSchema(schema.getItems(), schemas, group, version); + + Map properties = schema.getProperties(); + if (properties != null) { + Iterator> it = properties.entrySet().iterator(); + while (it.hasNext()) { + Entry entry = it.next(); + Schema property = entry.getValue(); + if (isGroupNotMatch(group, property.getGroup()) || isVersionNotMatch(version, property.getVersion())) { + it.remove(); + continue; + } + addSchema(property, schemas, group, version); + } + } + + addSchema(schema.getAdditionalPropertiesSchema(), schemas, group, version); + + List allOf = schema.getAllOf(); + if (allOf != null) { + for (Schema item : allOf) { + addSchema(item, schemas, group, version); + } + } + + List oneOf = schema.getOneOf(); + if (oneOf != null) { + for (Schema item : oneOf) { + addSchema(item, schemas, group, version); + } + } + + List anyOf = schema.getAnyOf(); + if (anyOf != null) { + for (Schema item : anyOf) { + addSchema(item, schemas, group, version); + } + } + + addSchema(schema.getNot(), schemas, group, version); + + Schema targetSchema = schema.getTargetSchema(); + if (targetSchema == null) { + return; + } + + targetSchema.addSourceSchema(schema); + + Schema newSchema = schemas.get(targetSchema); + if (newSchema == null) { + newSchema = targetSchema.clone(); + schemas.put(targetSchema, newSchema); + addSchema(newSchema, schemas, group, version); + } + } + + private void completeOperations(OpenAPI target) { + Map paths = target.getPaths(); + if (paths == null) { + return; + } + + Set allOperationIds = new HashSet<>(32); + Set allTags = new HashSet<>(32); + target.walkOperations(operation -> { + String operationId = operation.getOperationId(); + if (operationId != null) { + allOperationIds.add(operationId); + } + Set tags = operation.getTags(); + if (tags != null) { + allTags.addAll(tags); + } + }); + + OpenAPINamingStrategy strategy = getNamingStrategy(); + target.walkOperations(operation -> { + String id = operation.getOperationId(); + if (id != null) { + return; + } + id = strategy.generateOperationId(operation.getMeta(), target); + for (int i = 1; i < 100; i++) { + if (allOperationIds.contains(id)) { + id = strategy.resolveOperationIdConflict(i, id, operation.getMeta(), target); + } else { + allOperationIds.add(id); + break; + } + } + operation.setOperationId(id); + }); + + List tags = target.getTags(); + if (tags != null) { + ListIterator it = tags.listIterator(); + while (it.hasNext()) { + if (allTags.contains(it.next().getName())) { + continue; + } + it.remove(); + } + } + } + + private void completeModel(OpenAPI target) { + Info info = target.getInfo(); + if (info.getTitle() == null) { + info.setTitle("Dubbo OpenAPI"); + } + if (info.getVersion() == null) { + info.setVersion("v1"); + } + if (CollectionUtils.isEmptyMap(target.getPaths())) { + return; + } + ExternalDocs docs = target.getExternalDocs(); + if (docs.getUrl() == null && docs.getDescription() == null) { + docs.setUrl("../redoc/index.html?group=" + target.getGroup()).setDescription("ReDoc"); + } + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java new file mode 100644 index 00000000000..34e60c3d5d5 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java @@ -0,0 +1,463 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.rpc.protocol.tri.rest.openapi; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.logger.FluentLogger; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.nested.OpenAPIConfig; +import org.apache.dubbo.remoting.http12.ErrorResponse; +import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.remoting.http12.HttpUtils; +import org.apache.dubbo.remoting.http12.message.MediaType; +import org.apache.dubbo.remoting.http12.rest.ParamType; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.TripleHeaderEnum; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.Registration; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMapping; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.MethodsCondition; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.PathCondition; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.PathExpression; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.PropertyMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIDefinitionResolver.OpenAPIChain; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIDefinitionResolver.OperationChain; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIDefinitionResolver.OperationContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ApiResponse; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter.In; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.RequestBody; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Server; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Tag; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +final class DefinitionResolver { + + private static final FluentLogger LOG = FluentLogger.of(DefinitionResolver.class); + + private final ExtensionFactory extensionFactory; + private final ConfigFactory configFactory; + private final SchemaResolver schemaResolver; + private final OpenAPIDefinitionResolver[] resolvers; + + DefinitionResolver(FrameworkModel frameworkModel) { + extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class); + configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class); + schemaResolver = frameworkModel.getOrRegisterBean(SchemaResolver.class); + resolvers = extensionFactory.getExtensions(OpenAPIDefinitionResolver.class); + } + + public OpenAPI resolve(ServiceMeta serviceMeta, Collection> registrationsByMethod) { + OpenAPI definition = new OpenAPIChainImpl(resolvers, openAPI -> { + if (StringUtils.isEmpty(openAPI.getGroup())) { + openAPI.setGroup(Constants.DEFAULT_GROUP); + } + openAPI.setConfig(configFactory.getConfig(openAPI.getGroup())); + String service = serviceMeta.getServiceInterface(); + int index = service.lastIndexOf('.'); + String tagName = index == -1 ? service : service.substring(index + 1); + openAPI.addTag(new Tag().setName(tagName).setDescription(service)); + return openAPI; + }) + .resolve( + new OpenAPI().setMeta(serviceMeta).setGlobalConfig(configFactory.getGlobalConfig()), + serviceMeta); + if (definition == null) { + return null; + } + if (definition.getConfig() == null) { + definition.setConfig(configFactory.getConfig(definition.getGroup())); + } + + if (CollectionUtils.isEmpty(definition.getServers())) { + URL url = serviceMeta.getUrl(); + definition.addServer(new Server() + .setUrl("http://" + url.getHost() + ':' + url.getPort()) + .setDescription(Constants.DUBBO_DEFAULT_SERVER)); + } + + OperationContext context = new OperationContextImpl(definition, schemaResolver, extensionFactory); + for (List registrations : registrationsByMethod) { + String mainPath = null; + for (Registration registration : registrations) { + RequestMapping mapping = registration.getMapping(); + PathCondition pathCondition = mapping.getPathCondition(); + if (pathCondition == null) { + continue; + } + for (PathExpression expression : pathCondition.getExpressions()) { + String path = expression.toString(); + PathItem pathItem = definition.getOrAddPath(path); + String ref = pathItem.getRef(); + if (ref != null) { + path = ref; + pathItem = definition.getOrAddPath(path); + } + if (mainPath != null && expression.isDirect()) { + pathItem.setRef(mainPath); + continue; + } + MethodMeta methodMeta = registration.getMeta().getMethod(); + if (resolvePath(path, pathItem, definition, methodMeta, mapping, context)) { + mainPath = path; + } + } + } + } + + return definition; + } + + private boolean resolvePath( + String path, + PathItem pathItem, + OpenAPI openAPI, + MethodMeta methodMeta, + RequestMapping mapping, + OperationContext context) { + Collection httpMethods = null; + for (OpenAPIDefinitionResolver resolver : resolvers) { + httpMethods = resolver.resolve(pathItem, methodMeta, context); + if (httpMethods != null) { + break; + } + } + if (httpMethods == null) { + httpMethods = new LinkedList<>(); + for (String method : determineHttpMethods(openAPI, methodMeta, mapping)) { + httpMethods.add(HttpMethods.of(method.toUpperCase())); + } + } + + boolean added = false; + for (HttpMethods httpMethod : httpMethods) { + Operation operation = new Operation().setMeta(methodMeta); + Operation existingOperation = pathItem.getOperation(httpMethod); + if (existingOperation != null && existingOperation.getMeta() != null) { + LOG.internalWarn( + "Operation already exists, path='{}', httpMethod='{}', method={}", + path, + httpMethod, + methodMeta); + continue; + } + operation = new OperationChainImpl( + resolvers, op -> resolveOperation(path, httpMethod, op, openAPI, methodMeta, mapping)) + .resolve(operation, methodMeta, context); + if (operation != null) { + pathItem.addOperation(httpMethod, operation); + added = true; + } + } + return added; + } + + private Collection determineHttpMethods(OpenAPI openAPI, MethodMeta meta, RequestMapping mapping) { + Collection httpMethods = null; + MethodsCondition condition = mapping.getMethodsCondition(); + if (condition != null) { + httpMethods = condition.getMethods(); + } + if (httpMethods == null) { + String[] defaultHttpMethods = openAPI.getConfigValue(OpenAPIConfig::getDefaultHttpMethods); + if (defaultHttpMethods == null) { + httpMethods = Helper.guessHttpMethod(meta); + } else { + httpMethods = Arrays.asList(defaultHttpMethods); + } + } + return httpMethods; + } + + private Operation resolveOperation( + String path, + HttpMethods httpMethod, + Operation operation, + OpenAPI openAPI, + MethodMeta meta, + RequestMapping mapping) { + if (operation.getGroup() == null) { + operation.setGroup(openAPI.getGroup()); + } + for (Tag tag : openAPI.getTags()) { + operation.addTag(tag.getName()); + } + if (operation.getDeprecated() == null && meta.isHierarchyAnnotated(Deprecated.class)) { + operation.setDeprecated(true); + } + + ServiceMeta serviceMeta = meta.getServiceMeta(); + if (serviceMeta.getServiceVersion() != null) { + operation.addParameter(new Parameter(TripleHeaderEnum.SERVICE_GROUP.getName(), In.HEADER) + .setSchema(PrimitiveSchema.STRING.newSchema())); + } + if (serviceMeta.getServiceGroup() != null) { + operation.addParameter(new Parameter(TripleHeaderEnum.SERVICE_VERSION.getName(), In.HEADER) + .setSchema(PrimitiveSchema.STRING.newSchema())); + } + + List variables = Helper.extractVariables(path); + if (variables != null) { + for (String variable : variables) { + Parameter parameter = operation.getParameter(variable, In.PATH); + if (parameter == null) { + parameter = new Parameter(variable, In.PATH); + operation.addParameter(parameter); + } + parameter.setRequired(true); + if (parameter.getSchema() == null) { + parameter.setSchema(PrimitiveSchema.STRING.newSchema()); + } + } + } + + for (ParameterMeta paramMeta : meta.getParameters()) { + resolveParameter(httpMethod, operation, paramMeta, true); + } + + if (httpMethod.supportBody()) { + RequestBody body = operation.getRequestBody(); + if (body == null) { + body = new RequestBody(); + operation.setRequestBody(body); + } + if (CollectionUtils.isEmptyMap(body.getContents())) { + resolveRequestBody(body, openAPI, meta, mapping); + } + } + + if (CollectionUtils.isEmptyMap(operation.getResponses())) { + String[] httpStatusCodes = openAPI.getConfigValue(OpenAPIConfig::getDefaultHttpStatusCodes); + if (httpStatusCodes == null) { + httpStatusCodes = new String[] {"200", "400", "500"}; + } + for (String httpStatusCode : httpStatusCodes) { + ApiResponse response = operation.getOrAddResponse(httpStatusCode); + resolveResponse(httpStatusCode, response, openAPI, meta, mapping); + } + } + return operation; + } + + private void resolveParameter(HttpMethods httpMethod, Operation operation, ParameterMeta meta, boolean traverse) { + String name = meta.getName(); + if (name == null) { + return; + } + + NamedValueMeta valueMeta = meta.getNamedValueMeta(); + ParamType paramType = valueMeta.paramType(); + if (paramType == null) { + if (httpMethod.supportBody()) { + return; + } + paramType = ParamType.Param; + } + In in = Helper.toIn(paramType); + if (in == null) { + return; + } + + boolean simple = meta.isSimple(); + if (in != In.QUERY && !simple) { + return; + } + if (simple) { + Parameter parameter = operation.getParameter(name, in); + if (parameter == null) { + parameter = new Parameter(name, in); + operation.addParameter(parameter); + } + if (parameter.getRequired() == null) { + parameter.setRequired(valueMeta.required()); + } + Schema schema = parameter.getSchema(); + if (schema == null) { + parameter.setSchema(schema = schemaResolver.resolve(meta)); + } + if (schema.getDefaultValue() == null) { + schema.setDefaultValue(valueMeta.defaultValue()); + } + parameter.setMeta(meta); + return; + } + if (!traverse) { + return; + } + + BeanMeta beanMeta = meta.getBeanMeta(); + try { + for (ParameterMeta ctorParam : beanMeta.getConstructor().getParameters()) { + resolveParameter(httpMethod, operation, ctorParam, false); + } + } catch (Throwable ignored) { + } + for (PropertyMeta property : beanMeta.getProperties()) { + if ((property.getVisibility() & 0b001) == 0) { + continue; + } + resolveParameter(httpMethod, operation, property, false); + } + } + + private void resolveRequestBody(RequestBody body, OpenAPI openAPI, MethodMeta meta, RequestMapping mapping) { + Collection mediaTypes = null; + if (mapping.getConsumesCondition() != null) { + mediaTypes = mapping.getConsumesCondition().getMediaTypes(); + } + if (mediaTypes == null) { + String[] defaultMediaTypes = openAPI.getConfigValue(OpenAPIConfig::getDefaultConsumesMediaTypes); + if (defaultMediaTypes == null) { + mediaTypes = Collections.singletonList(MediaType.APPLICATION_JSON); + } else { + mediaTypes = Arrays.stream(defaultMediaTypes).map(MediaType::of).collect(Collectors.toList()); + } + } + out: + for (MediaType mediaType : mediaTypes) { + org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.MediaType content = + body.getOrAddContent(mediaType.getName()); + if (content.getSchema() == null) { + for (ParameterMeta paramMeta : meta.getParameters()) { + ParamType paramType = paramMeta.getNamedValueMeta().paramType(); + if (paramType == ParamType.Body) { + content.setSchema(schemaResolver.resolve(paramMeta)); + continue out; + } + } + + List paramMetas = new ArrayList<>(); + for (ParameterMeta paramMeta : meta.getParameters()) { + if (paramMeta.getNamedValueMeta().paramType() == null) { + paramMetas.add(paramMeta); + } + } + int size = paramMetas.size(); + if (size == 0) { + continue; + } + if (size == 1) { + content.setSchema(schemaResolver.resolve(paramMetas.get(0))); + } else { + content.setSchema(schemaResolver.resolve(paramMetas)); + } + } + } + } + + private void resolveResponse( + String httpStatusCode, ApiResponse response, OpenAPI openAPI, MethodMeta meta, RequestMapping mapping) { + int httpStatus = Integer.parseInt(httpStatusCode); + if (response.getDescription() == null) { + response.setDescription(HttpUtils.getStatusMessage(httpStatus)); + } + if (httpStatus > 201 && httpStatus < 400) { + return; + } + if (meta.getActualReturnType() == void.class) { + return; + } + + Collection mediaTypes = null; + if (mapping.getProducesCondition() != null) { + mediaTypes = mapping.getProducesCondition().getMediaTypes(); + } + if (mediaTypes == null) { + String[] defaultMediaTypes = openAPI.getConfigValue(OpenAPIConfig::getDefaultProducesMediaTypes); + if (defaultMediaTypes == null) { + mediaTypes = Collections.singletonList(MediaType.APPLICATION_JSON); + } else { + mediaTypes = Arrays.stream(defaultMediaTypes).map(MediaType::of).collect(Collectors.toList()); + } + } + for (MediaType mediaType : mediaTypes) { + org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.MediaType content = + response.getOrAddContent(mediaType.getName()); + if (content.getSchema() == null) { + if (httpStatus >= 400) { + content.setSchema(schemaResolver.resolve(ErrorResponse.class)); + } else { + content.setSchema(schemaResolver.resolve(meta.getReturnParameter())); + } + } + } + } + + private static final class OperationContextImpl extends AbstractContext implements OperationContext { + + OperationContextImpl(OpenAPI openAPI, SchemaResolver schemaResolver, ExtensionFactory extensionFactory) { + super(openAPI, schemaResolver, extensionFactory); + } + } + + private static final class OpenAPIChainImpl implements OpenAPIChain { + + private final OpenAPIDefinitionResolver[] resolvers; + private final Function fallback; + private int cursor; + + OpenAPIChainImpl(OpenAPIDefinitionResolver[] resolvers, Function fallback) { + this.resolvers = resolvers; + this.fallback = fallback; + } + + @Override + public OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta) { + if (cursor < resolvers.length) { + return resolvers[cursor++].resolve(openAPI, serviceMeta, this); + } + return fallback.apply(openAPI); + } + } + + private static final class OperationChainImpl implements OperationChain { + + private final OpenAPIDefinitionResolver[] resolvers; + private final Function fallback; + private int cursor; + + OperationChainImpl(OpenAPIDefinitionResolver[] resolvers, Function fallback) { + this.resolvers = resolvers; + this.fallback = fallback; + } + + @Override + public Operation resolve(Operation operation, MethodMeta methodMeta, OperationContext chain) { + if (cursor < resolvers.length) { + return resolvers[cursor++].resolve(operation, methodMeta, chain, this); + } + return fallback.apply(operation); + } + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java new file mode 100644 index 00000000000..62e2e5cce7a --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.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.dubbo.rpc.protocol.tri.rest.openapi; + +import org.apache.dubbo.common.extension.ExtensionLoader; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.common.utils.Pair; +import org.apache.dubbo.rpc.model.FrameworkModel; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +@SuppressWarnings("unchecked") +public final class ExtensionFactory { + + private final ExtensionLoader extensionLoader; + private final List extensions; + private final Map cache; + + public ExtensionFactory(FrameworkModel frameworkModel) { + extensionLoader = frameworkModel.getExtensionLoader(OpenAPIExtension.class); + extensions = extensionLoader.getActivateExtensions(); + cache = CollectionUtils.newConcurrentHashMap(); + } + + public boolean hasExtensions(Class type) { + return getExtensions(type).length > 0; + } + + public T[] getExtensions(Class type) { + return (T[]) cache.computeIfAbsent(type, k -> { + List list = new ArrayList<>(); + for (OpenAPIExtension extension : extensions) { + if (extension instanceof Supplier) { + extension = ((Supplier) extension).get(); + } + if (type.isInstance(extension)) { + list.add(extension); + } + } + return list.toArray((T[]) Array.newInstance(type, list.size())); + }); + } + + public T[] getExtensions(Class type, String group) { + if (group == null) { + return getExtensions(type); + } + return (T[]) cache.computeIfAbsent(Pair.of(type, group), k -> { + List list = new ArrayList<>(); + for (OpenAPIExtension extension : extensions) { + if (extension instanceof Supplier) { + extension = ((Supplier) extension).get(); + } + if (type.isInstance(extension) && accept(extension, group)) { + list.add(extension); + } + } + return list.toArray((T[]) Array.newInstance(type, list.size())); + }); + } + + public T getExtension(Class type, String name) { + OpenAPIExtension extension = extensionLoader.getExtension(name, true); + if (extension instanceof Supplier) { + extension = ((Supplier) extension).get(); + } + return type.isInstance(extension) ? (T) extension : null; + } + + private static boolean accept(OpenAPIExtension extension, String group) { + String[] groups = extension.getGroups(); + return groups == null || groups.length == 0 || Arrays.asList(groups).contains(group); + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java new file mode 100644 index 00000000000..1a17514acad --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.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.dubbo.rpc.protocol.tri.rest.openapi; + +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; +import org.apache.dubbo.remoting.http12.rest.ParamType; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter.In; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Server; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.apache.dubbo.remoting.http12.HttpMethods.DELETE; +import static org.apache.dubbo.remoting.http12.HttpMethods.GET; +import static org.apache.dubbo.remoting.http12.HttpMethods.PATCH; +import static org.apache.dubbo.remoting.http12.HttpMethods.POST; +import static org.apache.dubbo.remoting.http12.HttpMethods.PUT; + +public final class Helper { + + private static final String[][] VERBS_TABLE = { + { + GET.name(), + "get", + "load", + "fetch", + "read", + "retrieve", + "obtain", + "list", + "find", + "query", + "search", + "is", + "are", + "was", + "has", + "check", + "verify", + "test", + "can", + "should", + "need", + "allow", + "support", + "accept" + }, + {PUT.name(), "put", "replace"}, + {PATCH.name(), "patch", "update", "modify", "edit", "change", "set"}, + {DELETE.name(), "delete", "remove", "erase", "destroy", "drop"} + }; + + private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\{\\{([\\w.-]+)}}"); + + private Helper() {} + + public static Collection guessHttpMethod(MethodMeta method) { + String name = method.getMethod().getName(); + for (String[] verbs : VERBS_TABLE) { + for (int i = 1, len = verbs.length; i < len; i++) { + if (name.startsWith(verbs[i])) { + String httpMethod = verbs[0]; + if (GET.name().equals(httpMethod)) { + for (ParameterMeta parameter : method.getParameters()) { + ParamType paramType = parameter.getNamedValueMeta().paramType(); + if (paramType == null) { + if (parameter.isSimple()) { + continue; + } + return Arrays.asList(GET.name(), POST.name()); + } else { + switch (paramType) { + case Form: + case Part: + case Body: + return Collections.singletonList(POST.name()); + default: + } + } + } + } + return Collections.singletonList(httpMethod); + } + } + } + return Collections.singletonList(POST.name()); + } + + public static List extractVariables(String path) { + List variables = null; + for (int i = 0, len = path.length(), start = 0; i < len; i++) { + char c = path.charAt(i); + if (c == '{') { + start = i + 1; + } else if (start > 0 && c == '}') { + if (variables == null) { + variables = new ArrayList<>(); + } + variables.add(path.substring(start, i)); + start = 0; + } + } + return variables; + } + + public static In toIn(ParamType paramType) { + switch (paramType) { + case PathVariable: + return In.PATH; + case Param: + return In.QUERY; + case Header: + return In.HEADER; + case Cookie: + return In.COOKIE; + default: + return null; + } + } + + public static String formatSpecVersion(String version) { + if (version == null) { + return null; + } + if (version.startsWith("3.1")) { + return Constants.VERSION_31; + } + return Constants.VERSION_30; + } + + public static OpenAPIRequest formatRequest(OpenAPIRequest request) { + if (request == null) { + return new OpenAPIRequest(); + } + request.setGroup(trim(request.getGroup())); + request.setVersion(trim(request.getVersion())); + + String[] tag = trim(request.getTag()); + if (tag != null) { + Arrays.sort(tag); + } + request.setTag(tag); + + String[] service = trim(request.getService()); + if (service != null) { + Arrays.sort(service); + } + request.setService(service); + + request.setOpenapi(trim(request.getOpenapi())); + request.setFormat(trim(request.getFormat())); + return request; + } + + public static String parseFormat(String contentType) { + if (contentType != null) { + int index = contentType.indexOf('/'); + if (index > 0 && contentType.indexOf("htm", index) == -1) { + return contentType.substring(index + 1); + } + } + return "json"; + } + + public static String trim(String str) { + if (str == null || str.isEmpty()) { + return null; + } + str = str.trim(); + return str.isEmpty() ? null : str; + } + + public static String[] trim(String[] array) { + if (array == null) { + return null; + } + int len = array.length; + if (len == 0) { + return null; + } + int p = 0; + for (int i = 0; i < len; i++) { + String value = trim(array[i]); + if (value != null) { + array[p++] = value; + } + } + int newLen = p; + return newLen == len ? array : Arrays.copyOf(array, newLen); + } + + public static Map toProperties(String[] array) { + if (array == null) { + return Collections.emptyMap(); + } + int len = array.length; + if (len == 0) { + return Collections.emptyMap(); + } + Map properties = CollectionUtils.newLinkedHashMap(len); + for (String item : array) { + int index = item.indexOf('='); + if (index > 0) { + properties.put(trim(item.substring(0, index)), trim(item.substring(index + 1))); + } else { + properties.put(trim(item), null); + } + } + return properties; + } + + public static Server parseServer(String server) { + String url = null; + String description = null; + int equalIndex = server.indexOf('='); + if (equalIndex > 0) { + int index = server.indexOf("://"); + if (index == -1 || index > equalIndex) { + url = trim(server.substring(equalIndex + 1)); + description = trim(server.substring(0, equalIndex)); + } + } + if (url == null) { + url = trim(server); + } + return new Server().setDescription(description).setUrl(url); + } + + public static void setValue(Supplier getter, Consumer setter) { + String value = trim(getter.get()); + if (value != null) { + setter.accept(value); + } + } + + public static void setBoolValue(Supplier getter, Consumer setter) { + String value = trim(getter.get()); + if (value != null) { + setter.accept(StringUtils.toBoolean(value)); + } + } + + public static void setValue(AnnotationMeta schema, String key, Consumer setter) { + String value = trim(schema.getString(key)); + if (value != null) { + setter.accept(value); + } + } + + public static void setBoolValue(AnnotationMeta schema, String key, Consumer setter) { + Boolean value = schema.getBoolean(key); + if (Boolean.TRUE.equals(value)) { + setter.accept(true); + } + } + + public static String pathToRef(String path) { + StringBuilder sb = new StringBuilder(path.length() + 16); + sb.append("#/paths/"); + for (int i = 0, len = path.length(); i < len; i++) { + char c = path.charAt(i); + if (c == '/') { + sb.append('~').append('1'); + } else if (c == '~') { + sb.append('~').append('0'); + } else { + sb.append(c); + } + } + return sb.toString(); + } + + public static boolean isVersionGreaterOrEqual(String version1, String version2) { + int i = 0, j = 0, len1 = version1.length(), len2 = version2.length(); + while (i < len1 || j < len2) { + int num1 = 0; + while (i < len1) { + char c = version1.charAt(i); + if (Character.isDigit(c)) { + num1 = num1 * 10 + (c - '0'); + } else if (c == '.' || c == '-' || c == '_') { + i++; + break; + } + i++; + } + + int num2 = 0; + while (j < len2) { + char c = version2.charAt(j); + if (Character.isDigit(c)) { + num2 = num2 * 10 + (c - '0'); + } else if (c == '.' || c == '-' || c == '_') { + j++; + break; + } + j++; + } + + if (num1 < num2) { + return false; + } + } + return true; + } + + public static String render(String text, Function fn) { + if (text == null) { + return null; + } + Matcher matcher = PLACEHOLDER_PATTERN.matcher(text); + StringBuffer result = new StringBuffer(text.length()); + while (matcher.find()) { + String value = fn.apply(matcher.group(1)); + matcher.appendReplacement(result, value == null ? StringUtils.EMPTY_STRING : value); + } + matcher.appendTail(result); + return result.toString(); + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDefinitionResolver.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDefinitionResolver.java new file mode 100644 index 00000000000..19a3de71605 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDefinitionResolver.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.dubbo.rpc.protocol.tri.rest.openapi; + +import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem; + +import java.util.Collection; + +public interface OpenAPIDefinitionResolver extends OpenAPIExtension { + + OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta, OpenAPIChain chain); + + Collection resolve(PathItem pathItem, MethodMeta methodMeta, OperationContext context); + + Operation resolve(Operation operation, MethodMeta methodMeta, OperationContext context, OperationChain chain); + + interface OpenAPIChain { + + OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta); + } + + interface OperationChain { + + Operation resolve(Operation operation, MethodMeta methodMeta, OperationContext context); + } + + interface OperationContext { + + String getGroup(); + + OpenAPI getOpenAPI(); + + SchemaResolver getSchemaResolver(); + + ExtensionFactory getExtensionFactory(); + + T getAttribute(String name); + + T removeAttribute(String name); + + void setAttribute(String name, Object value); + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDocumentPublisher.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDocumentPublisher.java new file mode 100644 index 00000000000..c92502bb971 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDocumentPublisher.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.dubbo.rpc.protocol.tri.rest.openapi; + +import org.apache.dubbo.common.utils.Pair; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; + +import java.util.function.Function; + +public interface OpenAPIDocumentPublisher extends OpenAPIExtension { + + void publish(Function> fn); +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIExtension.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIExtension.java new file mode 100644 index 00000000000..0ab0b54b08a --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIExtension.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.dubbo.rpc.protocol.tri.rest.openapi; + +import org.apache.dubbo.common.extension.ExtensionScope; +import org.apache.dubbo.common.extension.SPI; + +@SPI(scope = ExtensionScope.FRAMEWORK) +public interface OpenAPIExtension { + + default String[] getGroups() { + return null; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIFilter.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIFilter.java new file mode 100644 index 00000000000..13e443942f0 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIFilter.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.dubbo.rpc.protocol.tri.rest.openapi; + +import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ApiResponse; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Header; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Node; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.RequestBody; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.SecurityScheme; + +public interface OpenAPIFilter extends OpenAPIExtension { + + default OpenAPI filterOpenAPI(OpenAPI openAPI, Context context) { + return openAPI; + } + + default PathItem filterPathItem(String key, PathItem pathItem, Context context) { + return pathItem; + } + + default Operation filterOperation(HttpMethods key, Operation operation, PathItem pathItem, Context context) { + return operation; + } + + default Parameter filterParameter(Parameter parameter, Operation operation, Context context) { + return parameter; + } + + default RequestBody filterRequestBody(RequestBody body, Operation operation, Context context) { + return body; + } + + default ApiResponse filterResponse(ApiResponse response, Operation operation, Context context) { + return response; + } + + default Header filterHeader(Header header, ApiResponse response, Operation operation, Context context) { + return header; + } + + default Schema filterSchema(Schema schema, Node node, Context context) { + return schema; + } + + default Schema filterSchemaProperty(String name, Schema schema, Schema owner, Context context) { + return schema; + } + + default SecurityScheme filterSecurityScheme(SecurityScheme securityScheme, Context context) { + return securityScheme; + } + + default OpenAPI filterOpenAPICompletion(OpenAPI openAPI, Context context) { + return openAPI; + } +} diff --git a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-consumer/src/main/java/org/apache/dubbo/demo/consumer/comp/DemoServiceComponent.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPINamingStrategy.java similarity index 57% rename from dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-consumer/src/main/java/org/apache/dubbo/demo/consumer/comp/DemoServiceComponent.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPINamingStrategy.java index 93d1eca356e..c71acd0dddb 100644 --- a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-consumer/src/main/java/org/apache/dubbo/demo/consumer/comp/DemoServiceComponent.java +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPINamingStrategy.java @@ -14,27 +14,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.demo.consumer.comp; +package org.apache.dubbo.rpc.protocol.tri.rest.openapi; -import org.apache.dubbo.config.annotation.DubboReference; -import org.apache.dubbo.demo.DemoService; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; -import java.util.concurrent.CompletableFuture; +public interface OpenAPINamingStrategy extends OpenAPIExtension { -import org.springframework.stereotype.Component; + String generateOperationId(MethodMeta methodMeta, OpenAPI openAPI); -@Component("demoServiceComponent") -public class DemoServiceComponent implements DemoService { - @DubboReference - private DemoService demoService; + String resolveOperationIdConflict(int attempt, String operationId, MethodMeta methodMeta, OpenAPI openAPI); - @Override - public String sayHello(String name) { - return demoService.sayHello(name); - } + String generateSchemaName(Class clazz, OpenAPI openAPI); - @Override - public CompletableFuture sayHelloAsync(String name) { - return null; - } + String resolveSchemaNameConflict(int attempt, String schemaName, Class clazz, OpenAPI openAPI); } diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequestHandler.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequestHandler.java new file mode 100644 index 00000000000..a89706cda8d --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequestHandler.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.dubbo.rpc.protocol.tri.rest.openapi; + +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.remoting.http12.HttpRequest; +import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.HttpResult; + +public interface OpenAPIRequestHandler extends OpenAPIExtension { + + default String[] getPaths() { + return StringUtils.EMPTY_STRING_ARRAY; + } + + HttpResult handle(String path, HttpRequest request, HttpResponse response); +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java new file mode 100644 index 00000000000..0e22369ba0d --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.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.dubbo.rpc.protocol.tri.rest.openapi; + +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.PropertyMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; + +public interface OpenAPISchemaPredicate extends OpenAPIExtension { + + default Boolean acceptClass(Class clazz, ParameterMeta parameter) { + return null; + } + + default Boolean acceptProperty(BeanMeta bean, PropertyMeta property) { + return null; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaResolver.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaResolver.java new file mode 100644 index 00000000000..e8518b0058c --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaResolver.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.dubbo.rpc.protocol.tri.rest.openapi; + +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; + +import java.lang.reflect.Type; + +public interface OpenAPISchemaResolver extends OpenAPIExtension { + + Schema resolve(ParameterMeta parameter, SchemaContext context, SchemaChain chain); + + interface SchemaChain { + + Schema resolve(ParameterMeta parameter, SchemaContext context); + } + + interface SchemaContext { + + void defineSchema(Class type, Schema schema); + + Schema resolve(ParameterMeta parameter); + + Schema resolve(Type type); + } +} diff --git a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/src/main/java/org/apache/dubbo/demo/graalvm/provider/DemoServiceImpl.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIScopeModelInitializer.java similarity index 63% rename from dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/src/main/java/org/apache/dubbo/demo/graalvm/provider/DemoServiceImpl.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIScopeModelInitializer.java index a360f6a5d91..2f6b7481357 100644 --- a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/src/main/java/org/apache/dubbo/demo/graalvm/provider/DemoServiceImpl.java +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIScopeModelInitializer.java @@ -14,17 +14,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.demo.graalvm.provider; +package org.apache.dubbo.rpc.protocol.tri.rest.openapi; -import org.apache.dubbo.graalvm.demo.DemoService; -import org.apache.dubbo.rpc.RpcContext; +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.model.ScopeModelInitializer; -public class DemoServiceImpl implements DemoService { +@Activate +public class OpenAPIScopeModelInitializer implements ScopeModelInitializer { @Override - public String sayHello(String name) { - System.out.println("Hello " + name + ", request from consumer: " - + RpcContext.getContext().getRemoteAddress()); - return "Hello " + name; + public void initializeFrameworkModel(FrameworkModel frameworkModel) { + frameworkModel.getBeanFactory().registerBeanDefinition(DefaultOpenAPIService.class); } } diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/PrimitiveSchema.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/PrimitiveSchema.java new file mode 100644 index 00000000000..81deb1693c0 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/PrimitiveSchema.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.dubbo.rpc.protocol.tri.rest.openapi; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema.Type; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Primitive Schema + * Format: Formats Registry + */ +public enum PrimitiveSchema { + STRING(String.class, Type.STRING), + BOOLEAN(Boolean.class, Type.BOOLEAN), + BYTE(Byte.class, Type.STRING, "byte"), + BINARY(Byte.class, Type.STRING, "binary"), + URI(java.net.URI.class, Type.STRING, "uri"), + URL(java.net.URL.class, Type.STRING, "url"), + EMAIL(String.class, Type.STRING, "email"), + PASSWORD(String.class, Type.STRING, "password"), + UUID(java.util.UUID.class, Type.STRING, "uuid"), + INT(Integer.class, Type.INTEGER, "int32"), + LONG(Long.class, Type.INTEGER, "int64"), + FLOAT(Float.class, Type.NUMBER, "float"), + DOUBLE(Double.class, Type.NUMBER, "double"), + INTEGER(java.math.BigInteger.class, Type.INTEGER), + DECIMAL(java.math.BigDecimal.class, Type.NUMBER, "number"), + NUMBER(Number.class, Type.NUMBER), + IP_V4(java.net.Inet4Address.class, Type.STRING, "ipv4"), + IP_V6(java.net.Inet6Address.class, Type.STRING, "ipv6"), + DATE_TIME(java.util.Date.class, Type.STRING, "date-time"), + DATE(java.time.LocalDate.class, Type.STRING, "date"), + TIME(java.time.LocalTime.class, Type.STRING, "time"), + DURATION(java.time.Duration.class, Type.STRING, "duration"), + FILE(java.io.File.class, Type.STRING, "binary"), + OBJECT(Object.class, Type.OBJECT), + ARRAY(Object[].class, Type.ARRAY); + + private static final Map TYPE_MAPPING = new ConcurrentHashMap<>(); + + static { + for (PrimitiveSchema schema : values()) { + TYPE_MAPPING.putIfAbsent(schema.keyClass, schema); + } + TYPE_MAPPING.put(boolean.class, BOOLEAN); + TYPE_MAPPING.put(byte.class, BYTE); + TYPE_MAPPING.put(char.class, STRING); + TYPE_MAPPING.put(Character.class, STRING); + TYPE_MAPPING.put(short.class, INT); + TYPE_MAPPING.put(Short.class, INT); + TYPE_MAPPING.put(int.class, INT); + TYPE_MAPPING.put(long.class, LONG); + TYPE_MAPPING.put(float.class, FLOAT); + TYPE_MAPPING.put(double.class, DOUBLE); + TYPE_MAPPING.put(byte[].class, BYTE); + + TYPE_MAPPING.put(java.util.Calendar.class, DATE_TIME); + TYPE_MAPPING.put(java.sql.Date.class, DATE_TIME); + TYPE_MAPPING.put(java.time.Instant.class, DATE_TIME); + TYPE_MAPPING.put(java.time.LocalDateTime.class, DATE_TIME); + TYPE_MAPPING.put(java.time.ZonedDateTime.class, DATE_TIME); + TYPE_MAPPING.put(java.time.OffsetDateTime.class, DATE_TIME); + TYPE_MAPPING.put(java.time.OffsetTime.class, TIME); + TYPE_MAPPING.put(java.time.Period.class, DURATION); + TYPE_MAPPING.put("javax.xml.datatype.XMLGregorianCalendar", DATE_TIME); + TYPE_MAPPING.put("org.joda.time.LocalDateTime", DATE_TIME); + TYPE_MAPPING.put("org.joda.time.ReadableDateTime", DATE_TIME); + TYPE_MAPPING.put("org.joda.time.DateTime", DATE_TIME); + TYPE_MAPPING.put("org.joda.time.LocalTime", TIME); + + TYPE_MAPPING.put(CharSequence.class, STRING); + TYPE_MAPPING.put(StringBuffer.class, STRING); + TYPE_MAPPING.put(StringBuilder.class, STRING); + TYPE_MAPPING.put(java.nio.charset.Charset.class, STRING); + TYPE_MAPPING.put(java.time.ZoneId.class, STRING); + TYPE_MAPPING.put(java.util.Currency.class, STRING); + TYPE_MAPPING.put(java.util.Locale.class, STRING); + TYPE_MAPPING.put(java.util.TimeZone.class, STRING); + TYPE_MAPPING.put(java.util.regex.Pattern.class, STRING); + + TYPE_MAPPING.put(java.io.InputStream.class, BYTE); + TYPE_MAPPING.put(java.net.InetAddress.class, IP_V4); + + TYPE_MAPPING.put("object", OBJECT); + } + + private final Class keyClass; + private final Type type; + private final String format; + + PrimitiveSchema(Class keyClass, Type type, String format) { + this.keyClass = keyClass; + this.type = type; + this.format = format; + } + + PrimitiveSchema(Class keyClass, Type type) { + this.keyClass = keyClass; + this.type = type; + format = null; + } + + public Schema newSchema() { + return new Schema().setType(type).setFormat(format); + } + + public static Schema newSchemaOf(Class type) { + PrimitiveSchema schema = TYPE_MAPPING.get(type); + if (schema == null) { + schema = TYPE_MAPPING.get(type.getName()); + } + return schema == null ? null : schema.newSchema(); + } + + public static boolean isPrimitive(Class type) { + return TYPE_MAPPING.containsKey(type); + } + + public static void addTypeMapping(Object key, PrimitiveSchema schema) { + TYPE_MAPPING.put(key, schema); + } +} diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/java/org/apache/dubbo/demo/provider/TripleServiceImpl.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ProtoEncoder.java similarity index 78% rename from dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/java/org/apache/dubbo/demo/provider/TripleServiceImpl.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ProtoEncoder.java index f1861454d1b..bffde4a8653 100644 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/java/org/apache/dubbo/demo/provider/TripleServiceImpl.java +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ProtoEncoder.java @@ -14,14 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.demo.provider; +package org.apache.dubbo.rpc.protocol.tri.rest.openapi; -import org.apache.dubbo.demo.TripleService; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; -public class TripleServiceImpl implements TripleService { +public final class ProtoEncoder { - @Override - public String hello() { - return "Triple!"; + public String encode(OpenAPI openAPI) { + return ""; } } diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.java new file mode 100644 index 00000000000..8bfddba6a76 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.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.dubbo.rpc.protocol.tri.rest.openapi; + +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RadixTree; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RadixTree.Match; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.PropertyMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.TypeParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver.SchemaChain; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver.SchemaContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; +import org.apache.dubbo.rpc.protocol.tri.rest.support.basic.Annotations; +import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit; +import org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils; + +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.lang.reflect.WildcardType; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.PrimitiveSchema.ARRAY; +import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.PrimitiveSchema.OBJECT; + +public final class SchemaResolver { + + private final ConfigFactory configFactory; + private final OpenAPISchemaResolver[] resolvers; + private final OpenAPISchemaPredicate[] predicates; + private final Map, Schema> schemaMap = CollectionUtils.newConcurrentHashMap(); + + private volatile RadixTree classFilter; + + public SchemaResolver(FrameworkModel frameworkModel) { + configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class); + ExtensionFactory extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class); + resolvers = extensionFactory.getExtensions(OpenAPISchemaResolver.class); + predicates = extensionFactory.getExtensions(OpenAPISchemaPredicate.class); + } + + public Schema resolve(Type type) { + return resolve(new TypeParameterMeta(type)); + } + + public Schema resolve(ParameterMeta parameter) { + return new SchemaChainImpl(resolvers, this::fallbackResolve).resolve(parameter, new SchemaContextImpl()); + } + + public Schema resolve(List parameters) { + Schema schema = OBJECT.newSchema(); + for (ParameterMeta parameter : parameters) { + String name = parameter.getName(); + if (name == null) { + return ARRAY.newSchema(); + } + schema.addProperty(name, resolve(parameter)); + } + return schema; + } + + private Schema fallbackResolve(ParameterMeta parameter) { + return doResolveType(parameter.getActualGenericType(), parameter); + } + + private Schema doResolveNestedType(Type nestedType, ParameterMeta parameter) { + return doResolveType(nestedType, new TypeParameterMeta(parameter.getToolKit(), nestedType)); + } + + private Schema doResolveType(Type type, ParameterMeta parameter) { + if (type instanceof Class) { + return doResolveClass((Class) type, parameter); + } + if (type instanceof ParameterizedType) { + ParameterizedType pType = (ParameterizedType) type; + Type rawType = pType.getRawType(); + if (rawType instanceof Class) { + Class clazz = (Class) rawType; + Type[] argTypes = pType.getActualTypeArguments(); + if (Iterable.class.isAssignableFrom(clazz)) { + Type itemType = TypeUtils.getActualGenericType(argTypes[0]); + return ARRAY.newSchema() + .addExtension(Constants.X_JAVA_CLASS, TypeUtils.toTypeString(type)) + .setItems(doResolveNestedType(itemType, parameter)); + } + + if (Map.class.isAssignableFrom(clazz)) { + return OBJECT.newSchema() + .addExtension(Constants.X_JAVA_CLASS, TypeUtils.toTypeString(type)) + .setAdditionalPropertiesSchema(doResolveNestedType(argTypes[1], parameter)); + } + + return doResolveClass(clazz, parameter); + } + } + if (type instanceof TypeVariable) { + return doResolveNestedType(((TypeVariable) type).getBounds()[0], parameter); + } + if (type instanceof WildcardType) { + return doResolveNestedType(((WildcardType) type).getUpperBounds()[0], parameter); + } + if (type instanceof GenericArrayType) { + return ARRAY.newSchema() + .addExtension(Constants.X_JAVA_CLASS, TypeUtils.toTypeString(type)) + .setItems(doResolveNestedType(((GenericArrayType) type).getGenericComponentType(), parameter)); + } + return OBJECT.newSchema(); + } + + private Schema doResolveClass(Class clazz, ParameterMeta parameter) { + Schema schema = PrimitiveSchema.newSchemaOf(clazz); + if (schema != null) { + return schema; + } + + if (clazz.isArray()) { + schema = ARRAY.newSchema(); + if (!PrimitiveSchema.isPrimitive(clazz.getComponentType())) { + schema.addExtension(Constants.X_JAVA_CLASS, TypeUtils.toTypeString(clazz)); + } + return schema.setItems(doResolveNestedType(clazz.getComponentType(), parameter)); + } + + Schema existingSchema = schemaMap.get(clazz); + if (existingSchema != null) { + return new Schema().setTargetSchema(existingSchema); + } + + if (isClassExcluded(clazz)) { + schema = OBJECT.newSchema().addExtension(Constants.X_JAVA_CLASS, TypeUtils.toTypeString(clazz)); + schemaMap.put(clazz, schema); + return schema; + } + + TypeParameterMeta typeParameter = new TypeParameterMeta(clazz); + for (OpenAPISchemaPredicate predicate : predicates) { + Boolean accepted = predicate.acceptClass(clazz, typeParameter); + if (accepted == null) { + continue; + } + if (accepted) { + break; + } else { + schema = OBJECT.newSchema().addExtension(Constants.X_JAVA_CLASS, TypeUtils.toTypeString(clazz)); + schemaMap.put(clazz, schema); + return schema; + } + } + + if (clazz.isEnum()) { + schema = PrimitiveSchema.STRING.newSchema().setJavaType(clazz); + for (Object value : clazz.getEnumConstants()) { + schema.addEnumeration(value); + } + schemaMap.put(clazz, schema); + return schema.clone(); + } + + Boolean flatten = configFactory.getGlobalConfig().getSchemaFlatten(); + if (flatten == null) { + AnnotationMeta anno = typeParameter.getAnnotation(Annotations.Schema); + flatten = anno != null && anno.getBoolean("flatten"); + } + + return new Schema().setTargetSchema(doResolveBeanClass(parameter.getToolKit(), clazz, flatten)); + } + + private Schema doResolveBeanClass(RestToolKit toolKit, Class clazz, boolean flatten) { + Schema beanSchema = OBJECT.newSchema().setJavaType(clazz); + schemaMap.put(clazz, beanSchema); + BeanMeta beanMeta = new BeanMeta(toolKit, clazz, flatten); + out: + for (PropertyMeta property : beanMeta.getProperties()) { + boolean fallback = true; + for (OpenAPISchemaPredicate predicate : predicates) { + Boolean accepted = predicate.acceptProperty(beanMeta, property); + if (accepted == null) { + continue; + } + if (accepted) { + fallback = false; + break; + } else { + continue out; + } + } + + if (fallback) { + int visibility = property.getVisibility(); + if ((visibility & 0b001) == 0 || (visibility & 0b110) == 0) { + continue; + } + } + beanSchema.addProperty(property.getName(), resolve(property)); + } + + if (flatten) { + return beanSchema; + } + Class superClass = clazz.getSuperclass(); + if (superClass == null || superClass == Object.class || TypeUtils.isSystemType(superClass)) { + return beanSchema; + } + + return beanSchema.addAllOf(resolve(superClass)); + } + + private boolean isClassExcluded(Class clazz) { + RadixTree classFilter = this.classFilter; + if (classFilter == null) { + synchronized (this) { + classFilter = this.classFilter; + if (classFilter == null) { + classFilter = new RadixTree<>('.'); + for (String prefix : TypeUtils.getSystemPrefixes()) { + addPath(classFilter, prefix); + } + String[] excludes = configFactory.getGlobalConfig().getSchemaClassExcludes(); + if (excludes != null) { + for (String exclude : excludes) { + addPath(classFilter, exclude); + } + } + this.classFilter = classFilter; + } + } + } + + List> matches = classFilter.match('.' + clazz.getName()); + int size = matches.size(); + if (size == 0) { + return false; + } else if (size > 1) { + Collections.sort(matches); + } + return matches.get(0).getValue(); + } + + public static void addPath(RadixTree tree, String path) { + if (path == null) { + return; + } + int size = path.length(); + if (size == 0) { + return; + } + boolean value = true; + if (path.charAt(0) == '!') { + path = path.substring(1); + size--; + value = false; + } + if (path.charAt(size - 1) == '.') { + path += "**"; + } + tree.addPath(path, value); + } + + private static final class SchemaChainImpl implements SchemaChain { + + private final OpenAPISchemaResolver[] resolvers; + private final Function fallback; + private int cursor; + + SchemaChainImpl(OpenAPISchemaResolver[] resolvers, Function fallback) { + this.resolvers = resolvers; + this.fallback = fallback; + } + + @Override + public Schema resolve(ParameterMeta parameter, SchemaContext context) { + if (cursor < resolvers.length) { + return resolvers[cursor++].resolve(parameter, context, this); + } + return fallback.apply(parameter); + } + } + + private final class SchemaContextImpl implements SchemaContext { + + @Override + public void defineSchema(Class type, Schema schema) { + schemaMap.putIfAbsent(type, schema); + } + + @Override + public Schema resolve(ParameterMeta parameter) { + return SchemaResolver.this.resolve(parameter); + } + + @Override + public Schema resolve(Type type) { + return SchemaResolver.this.resolve(type); + } + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ApiResponse.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ApiResponse.java new file mode 100644 index 00000000000..525e25b66e7 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ApiResponse.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.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; + +import java.util.LinkedHashMap; +import java.util.Map; + +public final class ApiResponse extends Node { + + private String ref; + private String description; + private Map headers; + private Map contents; + + public String getRef() { + return ref; + } + + public ApiResponse setRef(String ref) { + this.ref = ref; + return this; + } + + public String getDescription() { + return description; + } + + public ApiResponse setDescription(String description) { + this.description = description; + return this; + } + + public Map getHeaders() { + return headers; + } + + public Header getHeader(String name) { + return headers == null ? null : headers.get(name); + } + + public ApiResponse setHeaders(Map headers) { + this.headers = headers; + return this; + } + + public ApiResponse addHeader(String name, Header header) { + if (headers == null) { + headers = new LinkedHashMap<>(); + } + headers.put(name, header); + return this; + } + + public ApiResponse removeHeader(String name) { + if (headers != null) { + headers.remove(name); + } + return this; + } + + public Map getContents() { + return contents; + } + + public MediaType getContent(String name) { + return contents == null ? null : contents.get(name); + } + + public MediaType getOrAddContent(String name) { + if (contents == null) { + contents = new LinkedHashMap<>(); + } + return contents.computeIfAbsent(name, k -> new MediaType()); + } + + public ApiResponse setContents(Map contents) { + this.contents = contents; + return this; + } + + public ApiResponse addContent(String name, MediaType content) { + if (contents == null) { + contents = new LinkedHashMap<>(); + } + contents.put(name, content); + return this; + } + + public ApiResponse removeContent(String name) { + if (contents != null) { + contents.remove(name); + } + return this; + } + + @Override + public ApiResponse clone() { + ApiResponse clone = super.clone(); + clone.contents = clone(contents); + return clone; + } + + @Override + public Map writeTo(Map node, Context context) { + write(node, "description", description); + write(node, "content", contents, context); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Components.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Components.java new file mode 100644 index 00000000000..46567b7e40e --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Components.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.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.TreeMap; + +public final class Components extends Node { + + private Map schemas; + private Map securitySchemes; + + public Map getSchemas() { + return schemas; + } + + public Components setSchemas(Map schemas) { + this.schemas = schemas; + return this; + } + + public Components addSchema(String name, Schema schema) { + if (schemas == null) { + schemas = new TreeMap<>(); + } + schemas.put(name, schema); + return this; + } + + public Components removeSchema(String name) { + if (schemas != null) { + schemas.remove(name); + } + return this; + } + + public Map getSecuritySchemes() { + return securitySchemes; + } + + public Components setSecuritySchemes(Map securitySchemes) { + this.securitySchemes = securitySchemes; + return this; + } + + public Components addSecurityScheme(String name, SecurityScheme securityScheme) { + if (securitySchemes == null) { + securitySchemes = new LinkedHashMap<>(); + } + securitySchemes.put(name, securityScheme); + return this; + } + + public Components removeSecurityScheme(String name) { + if (securitySchemes != null) { + securitySchemes.remove(name); + } + return this; + } + + @Override + public Components clone() { + Components clone = super.clone(); + clone.schemas = clone(schemas); + clone.securitySchemes = clone(securitySchemes); + return clone; + } + + @Override + public Map writeTo(Map node, Context context) { + write(node, "schemas", schemas, context); + write(node, "securitySchemes", securitySchemes, context); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-demo/dubbo-demo-interface/src/main/java/po/User.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Contact.java similarity index 51% rename from dubbo-demo/dubbo-demo-interface/src/main/java/po/User.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Contact.java index d5a6326c900..897e28b9cd0 100644 --- a/dubbo-demo/dubbo-demo-interface/src/main/java/po/User.java +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Contact.java @@ -14,59 +14,51 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package po; +package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -import java.io.Serializable; -import java.util.Objects; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; -public class User implements Serializable { +import java.util.Map; - private Long id; +public final class Contact extends Node { private String name; - - public User() {} - - public User(Long id, String name) { - this.id = id; - this.name = name; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } + private String url; + private String email; public String getName() { return name; } - public void setName(String name) { + public Contact setName(String name) { this.name = name; + return this; } - public static User getInstance() { - return new User(1l, "dubbo-rest"); + public String getUrl() { + return url; } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - User user = (User) o; - return Objects.equals(id, user.id) && Objects.equals(name, user.name); + public Contact setUrl(String url) { + this.url = url; + return this; } - @Override - public int hashCode() { - return Objects.hash(id, name); + public String getEmail() { + return email; + } + + public Contact setEmail(String email) { + this.email = email; + return this; } @Override - public String toString() { - return "User (" + "id=" + id + ", name='" + name + '\'' + ')'; + public Map writeTo(Map node, Context context) { + write(node, "name", name); + write(node, "url", url); + write(node, "email", email); + writeExtensions(node); + return node; } } diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Discriminator.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Discriminator.java new file mode 100644 index 00000000000..e658f28c119 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Discriminator.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.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; + +import java.util.LinkedHashMap; +import java.util.Map; + +public final class Discriminator extends Node { + + private String propertyName; + private Map mapping; + + public String getPropertyName() { + return propertyName; + } + + public Discriminator setPropertyName(String propertyName) { + this.propertyName = propertyName; + return this; + } + + public Map getMapping() { + return mapping; + } + + public Discriminator setMapping(Map mapping) { + this.mapping = mapping; + return this; + } + + public Discriminator addMapping(String key, String value) { + if (mapping == null) { + mapping = new LinkedHashMap<>(); + } + mapping.put(key, value); + return this; + } + + public Discriminator removeMapping(String key) { + if (mapping != null) { + mapping.remove(key); + } + return this; + } + + @Override + public Discriminator clone() { + Discriminator clone = super.clone(); + if (mapping != null) { + clone.setMapping(new LinkedHashMap<>(mapping)); + } + return clone; + } + + @Override + public Map writeTo(Map node, Context context) { + write(node, "propertyName", propertyName); + write(node, "mapping", mapping); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Encoding.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Encoding.java new file mode 100644 index 00000000000..578c086de54 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Encoding.java @@ -0,0 +1,131 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; + +import java.util.LinkedHashMap; +import java.util.Map; + +public final class Encoding extends Node { + + public enum Style { + FORM("form"), + SPACE_DELIMITED("spaceDelimited"), + PIPE_DELIMITED("pipeDelimited"), + DEEP_OBJECT("deepObject"); + + private final String value; + + Style(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + + private String contentType; + private Map headers; + private Style style; + private Boolean explode; + private Boolean allowReserved; + + public String getContentType() { + return contentType; + } + + public Encoding setContentType(String contentType) { + this.contentType = contentType; + return this; + } + + public Map getHeaders() { + return headers; + } + + public Parameter getHeader(String name) { + return headers == null ? null : headers.get(name); + } + + public Encoding setHeaders(Map headers) { + this.headers = headers; + return this; + } + + public Encoding addHeader(String name, Parameter header) { + if (headers == null) { + headers = new LinkedHashMap<>(); + } + headers.put(name, header); + return this; + } + + public Encoding removeHeader(String name) { + if (headers != null) { + headers.remove(name); + } + return this; + } + + public Style getStyle() { + return style; + } + + public Encoding setStyle(Style style) { + this.style = style; + return this; + } + + public Boolean getExplode() { + return explode; + } + + public Encoding setExplode(Boolean explode) { + this.explode = explode; + return this; + } + + public Boolean getAllowReserved() { + return allowReserved; + } + + public Encoding setAllowReserved(Boolean allowReserved) { + this.allowReserved = allowReserved; + return this; + } + + @Override + public Encoding clone() { + Encoding clone = super.clone(); + clone.headers = clone(headers); + return clone; + } + + @Override + public Map writeTo(Map encoding, Context context) { + write(encoding, "contentType", contentType); + write(encoding, "headers", headers, context); + write(encoding, "style", style); + write(encoding, "explode", explode); + write(encoding, "allowReserved", allowReserved); + writeExtensions(encoding); + return encoding; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Example.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Example.java new file mode 100644 index 00000000000..03dd029b55c --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Example.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.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; + +import java.util.Map; + +public final class Example extends Node { + + private String summary; + private String description; + private Object value; + private String externalValue; + + public String getSummary() { + return summary; + } + + public Example setSummary(String summary) { + this.summary = summary; + return this; + } + + public String getDescription() { + return description; + } + + public Example setDescription(String description) { + this.description = description; + return this; + } + + public Object getValue() { + return value; + } + + public Example setValue(Object value) { + this.value = value; + return this; + } + + public String getExternalValue() { + return externalValue; + } + + public Example setExternalValue(String externalValue) { + this.externalValue = externalValue; + return this; + } + + @Override + public Map writeTo(Map exampleNode, Context context) { + write(exampleNode, "summary", summary); + write(exampleNode, "description", description); + write(exampleNode, "value", value); + write(exampleNode, "externalValue", externalValue); + writeExtensions(exampleNode); + return exampleNode; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ExternalDocs.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ExternalDocs.java new file mode 100644 index 00000000000..a4824648696 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ExternalDocs.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.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; + +import java.util.Map; + +public final class ExternalDocs extends Node { + + private String description; + private String url; + + public String getDescription() { + return description; + } + + public ExternalDocs setDescription(String description) { + this.description = description; + return this; + } + + public String getUrl() { + return url; + } + + public ExternalDocs setUrl(String url) { + this.url = url; + return this; + } + + @Override + public Map writeTo(Map node, Context context) { + write(node, "description", description); + write(node, "url", url); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Header.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Header.java new file mode 100644 index 00000000000..90a0c764d46 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Header.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.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; + +import java.util.LinkedHashMap; +import java.util.Map; + +public final class Header extends Node
{ + + public enum Style { + SIMPLE("simple"); + + private final String value; + + Style(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + + private String description; + private Boolean required; + private Boolean deprecated; + private Boolean allowEmptyValue; + private final Style style = Style.SIMPLE; + private Boolean explode; + private Schema schema; + private Object example; + private Map examples; + private Map contents; + + public String getDescription() { + return description; + } + + public Header setDescription(String description) { + this.description = description; + return this; + } + + public Boolean getRequired() { + return required; + } + + public Header setRequired(Boolean required) { + this.required = required; + return this; + } + + public Boolean getDeprecated() { + return deprecated; + } + + public Header setDeprecated(Boolean deprecated) { + this.deprecated = deprecated; + return this; + } + + public Boolean getAllowEmptyValue() { + return allowEmptyValue; + } + + public Header setAllowEmptyValue(Boolean allowEmptyValue) { + this.allowEmptyValue = allowEmptyValue; + return this; + } + + public Style getStyle() { + return style; + } + + public Boolean getExplode() { + return explode; + } + + public Header setExplode(Boolean explode) { + this.explode = explode; + return this; + } + + public Schema getSchema() { + return schema; + } + + public Header setSchema(Schema schema) { + this.schema = schema; + return this; + } + + public Object getExample() { + return example; + } + + public Header setExample(Object example) { + this.example = example; + return this; + } + + public Map getExamples() { + return examples; + } + + public Header setExamples(Map examples) { + this.examples = examples; + return this; + } + + public Header addExample(String name, Example example) { + if (examples == null) { + examples = new LinkedHashMap<>(); + } + examples.put(name, example); + return this; + } + + public Header removeExample(String name) { + if (examples != null) { + examples.remove(name); + } + return this; + } + + public Map getContents() { + return contents; + } + + public MediaType getContent(String name) { + return contents == null ? null : contents.get(name); + } + + public Header setContents(Map contents) { + this.contents = contents; + return this; + } + + public Header addContent(String name, MediaType content) { + if (contents == null) { + contents = new LinkedHashMap<>(); + } + contents.put(name, content); + return this; + } + + public Header removeContent(String name) { + if (contents != null) { + contents.remove(name); + } + return this; + } + + @Override + public Header clone() { + Header clone = super.clone(); + clone.schema = clone(schema); + clone.examples = clone(examples); + clone.contents = clone(contents); + return clone; + } + + @Override + public Map writeTo(Map node, Context context) { + write(node, "description", description); + write(node, "required", required); + write(node, "deprecated", deprecated); + write(node, "allowEmptyValue", allowEmptyValue); + write(node, "style", style); + write(node, "explode", explode); + write(node, "schema", schema, context); + write(node, "example", example); + write(node, "examples", examples, context); + write(node, "content", contents, context); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Info.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Info.java new file mode 100644 index 00000000000..fd1cc84ce47 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Info.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.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; + +import java.util.Map; + +public final class Info extends Node { + + private String title; + private String summary; + private String description; + private String termsOfService; + private Contact contact; + private License license; + private String version; + + public String getTitle() { + return title; + } + + public Info setTitle(String title) { + this.title = title; + return this; + } + + public String getSummary() { + return summary; + } + + public Info setSummary(String summary) { + this.summary = summary; + return this; + } + + public String getDescription() { + return description; + } + + public Info setDescription(String description) { + this.description = description; + return this; + } + + public String getTermsOfService() { + return termsOfService; + } + + public Info setTermsOfService(String termsOfService) { + this.termsOfService = termsOfService; + return this; + } + + public Contact getContact() { + return contact; + } + + public Info setContact(Contact contact) { + this.contact = contact; + return this; + } + + public License getLicense() { + return license; + } + + public Info setLicense(License license) { + this.license = license; + return this; + } + + public String getVersion() { + return version; + } + + public Info setVersion(String version) { + this.version = version; + return this; + } + + @Override + public Info clone() { + Info clone = super.clone(); + clone.contact = clone(contact); + clone.license = clone(license); + return clone; + } + + @Override + public Map writeTo(Map node, Context context) { + write(node, "title", title); + write(node, "summary", summary); + write(node, "description", description); + write(node, "termsOfService", termsOfService); + write(node, "contact", contact, context); + write(node, "license", license, context); + write(node, "version", version); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-demo/dubbo-demo-interface/src/main/java/po/TestPO.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/License.java similarity index 55% rename from dubbo-demo/dubbo-demo-interface/src/main/java/po/TestPO.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/License.java index 29a139f08ab..36c68f0b564 100644 --- a/dubbo-demo/dubbo-demo-interface/src/main/java/po/TestPO.java +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/License.java @@ -14,51 +14,40 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package po; +package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -public class TestPO { - private String name; - private String address; - private int age; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; - public TestPO(String name, String address, int age) { - this.name = name; - this.address = address; - this.age = age; - } +import java.util.Map; - public TestPO() {} +public final class License extends Node { + + private String name; + private String url; public String getName() { return name; } - public void setName(String name) { + public License setName(String name) { this.name = name; + return this; } - public String getAddress() { - return address; - } - - public void setAddress(String address) { - this.address = address; - } - - public int getAge() { - return age; - } - - public void setAge(int age) { - this.age = age; + public String getUrl() { + return url; } - public static TestPO getInstance() { - return new TestPO("dubbo", "hangzhou", 10); + public License setUrl(String url) { + this.url = url; + return this; } @Override - public String toString() { - return "TestPO{" + "name='" + name + '\'' + ", address='" + address + '\'' + ", age=" + age + '}'; + public Map writeTo(Map node, Context context) { + write(node, "name", name); + write(node, "url", url); + writeExtensions(node); + return node; } } diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/MediaType.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/MediaType.java new file mode 100644 index 00000000000..85477145261 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/MediaType.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.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; + +import java.util.LinkedHashMap; +import java.util.Map; + +public final class MediaType extends Node { + + private Schema schema; + private Object example; + private Map examples; + private Map encoding; + + public Schema getSchema() { + return schema; + } + + public MediaType setSchema(Schema schema) { + this.schema = schema; + return this; + } + + public Object getExample() { + return example; + } + + public MediaType setExample(Object example) { + this.example = example; + return this; + } + + public Map getExamples() { + return examples; + } + + public MediaType setExamples(Map examples) { + this.examples = examples; + return this; + } + + public MediaType addExample(String name, Example example) { + if (examples == null) { + examples = new LinkedHashMap<>(); + } + examples.put(name, example); + return this; + } + + public MediaType removeExample(String name) { + if (examples != null) { + examples.remove(name); + } + return this; + } + + public Map getEncoding() { + return encoding; + } + + public MediaType setEncoding(Map encoding) { + this.encoding = encoding; + return this; + } + + public MediaType addEncoding(String name, Encoding encoding) { + if (this.encoding == null) { + this.encoding = new LinkedHashMap<>(); + } + this.encoding.put(name, encoding); + return this; + } + + public MediaType removeEncoding(String name) { + if (encoding != null) { + encoding.remove(name); + } + return this; + } + + @Override + public MediaType clone() { + MediaType clone = super.clone(); + clone.schema = clone(schema); + clone.examples = clone(examples); + clone.encoding = clone(encoding); + return clone; + } + + @Override + public Map writeTo(Map node, Context context) { + write(node, "schema", schema, context); + write(node, "example", example); + write(node, "examples", examples, context); + write(node, "encoding", encoding, context); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java new file mode 100644 index 00000000000..45fa1ae7aea --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.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.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.common.utils.ToStringUtils; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public abstract class Node> implements Cloneable { + + private Map extensions; + + public Map getExtensions() { + return extensions; + } + + @SuppressWarnings("unchecked") + public T addExtension(String name, Object value) { + Map extensions = this.extensions; + if (extensions == null) { + this.extensions = extensions = new LinkedHashMap<>(); + } + extensions.put(name, value); + return (T) this; + } + + @SuppressWarnings("unchecked") + public T addExtensions(Map extensions) { + if (extensions == null || extensions.isEmpty()) { + return (T) this; + } + + Map thisExtensions = this.extensions; + if (thisExtensions == null) { + this.extensions = new LinkedHashMap<>(extensions); + } else { + for (Map.Entry entry : extensions.entrySet()) { + thisExtensions.putIfAbsent(entry.getKey(), entry.getValue()); + } + } + return (T) this; + } + + public void removeExtension(String name) { + if (extensions != null) { + extensions.remove(name); + } + } + + @SuppressWarnings("unchecked") + public T setExtensions(Map extensions) { + if (extensions != null) { + this.extensions = new LinkedHashMap<>(extensions); + } + return (T) this; + } + + @Override + @SuppressWarnings("unchecked") + public T clone() { + try { + T clone = (T) super.clone(); + if (extensions != null) { + clone.setExtensions(extensions); + } + return clone; + } catch (CloneNotSupportedException e) { + throw new UnsupportedOperationException(e); + } + } + + @Override + public String toString() { + return ToStringUtils.printToString(this); + } + + public static > T clone(T node) { + return node == null ? null : node.clone(); + } + + public static > List clone(List list) { + if (list == null) { + return null; + } + int size = list.size(); + if (size == 0) { + return new ArrayList<>(); + } + List clone = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + clone.add(list.get(i).clone()); + } + return clone; + } + + public static > Map clone(Map map) { + if (map == null) { + return null; + } + int size = map.size(); + if (size == 0) { + return new LinkedHashMap<>(); + } + Map clone = newMap(size); + for (Map.Entry entry : map.entrySet()) { + clone.put(entry.getKey(), entry.getValue().clone()); + } + return clone; + } + + protected static void write(Map node, String name, Object value) { + if (value == null || "".equals(value)) { + return; + } + node.put(name, value instanceof Set ? ((Set) value).toArray() : value); + } + + protected static void write(Map node, String name, Node value, Context context) { + if (value == null) { + return; + } + Map valueMap = value.writeTo(new LinkedHashMap<>(), context); + if (valueMap == null || valueMap.isEmpty()) { + return; + } + node.put(name, valueMap); + } + + protected static void write(Map node, String name, List> value, Context context) { + if (value == null) { + return; + } + int size = value.size(); + if (size > 0) { + List> list = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + Map valueMap = value.get(i).writeTo(new LinkedHashMap<>(), context); + if (valueMap == null || valueMap.isEmpty()) { + continue; + } + list.add(valueMap); + } + node.put(name, list); + } + } + + protected static void write( + Map node, String name, Map> value, Context context) { + if (value == null) { + return; + } + int size = value.size(); + if (size > 0) { + Map> map = newMap(size); + for (Map.Entry> entry : value.entrySet()) { + Map valueMap = entry.getValue().writeTo(new LinkedHashMap<>(), context); + if (valueMap == null || valueMap.isEmpty()) { + continue; + } + map.put(entry.getKey(), valueMap); + } + node.put(name, map); + } + } + + protected static Map newMap(int capacity) { + return new LinkedHashMap<>(capacity < 3 ? capacity + 1 : (int) (capacity / 0.75F + 1.0F)); + } + + protected final void writeExtensions(Map node) { + if (extensions == null) { + return; + } + node.putAll(extensions); + } + + public abstract Map writeTo(Map node, Context context); +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlow.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlow.java new file mode 100644 index 00000000000..4ef8578e518 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlow.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.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; + +import java.util.LinkedHashMap; +import java.util.Map; + +public final class OAuthFlow extends Node { + + private String authorizationUrl; + private String tokenUrl; + private String refreshUrl; + private Map scopes; + + public String getAuthorizationUrl() { + return authorizationUrl; + } + + public OAuthFlow setAuthorizationUrl(String authorizationUrl) { + this.authorizationUrl = authorizationUrl; + return this; + } + + public String getTokenUrl() { + return tokenUrl; + } + + public OAuthFlow setTokenUrl(String tokenUrl) { + this.tokenUrl = tokenUrl; + return this; + } + + public String getRefreshUrl() { + return refreshUrl; + } + + public OAuthFlow setRefreshUrl(String refreshUrl) { + this.refreshUrl = refreshUrl; + return this; + } + + public Map getScopes() { + return scopes; + } + + public OAuthFlow setScopes(Map scopes) { + this.scopes = scopes; + return this; + } + + public OAuthFlow addScope(String name, String description) { + if (scopes == null) { + scopes = new LinkedHashMap<>(); + } + scopes.put(name, description); + return this; + } + + public void removeScope(String name) { + if (scopes != null) { + scopes.remove(name); + } + } + + @Override + public OAuthFlow clone() { + OAuthFlow clone = super.clone(); + if (scopes != null) { + clone.scopes = new LinkedHashMap<>(scopes); + } + return clone; + } + + @Override + public Map writeTo(Map node, Context context) { + write(node, "authorizationUrl", authorizationUrl); + write(node, "tokenUrl", tokenUrl); + write(node, "refreshUrl", refreshUrl); + write(node, "scopes", scopes); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlows.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlows.java new file mode 100644 index 00000000000..619c1cb10eb --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlows.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.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; + +import java.util.Map; + +public final class OAuthFlows extends Node { + + private OAuthFlow implicit; + private OAuthFlow password; + private OAuthFlow clientCredentials; + private OAuthFlow authorizationCode; + + public OAuthFlow getImplicit() { + return implicit; + } + + public OAuthFlows setImplicit(OAuthFlow implicit) { + this.implicit = implicit; + return this; + } + + public OAuthFlow getPassword() { + return password; + } + + public OAuthFlows setPassword(OAuthFlow password) { + this.password = password; + return this; + } + + public OAuthFlow getClientCredentials() { + return clientCredentials; + } + + public OAuthFlows setClientCredentials(OAuthFlow clientCredentials) { + this.clientCredentials = clientCredentials; + return this; + } + + public OAuthFlow getAuthorizationCode() { + return authorizationCode; + } + + public OAuthFlows setAuthorizationCode(OAuthFlow authorizationCode) { + this.authorizationCode = authorizationCode; + return this; + } + + @Override + public OAuthFlows clone() { + OAuthFlows clone = super.clone(); + clone.implicit = clone(implicit); + clone.password = clone(password); + clone.clientCredentials = clone(clientCredentials); + clone.authorizationCode = clone(authorizationCode); + return clone; + } + + @Override + public Map writeTo(Map node, Context context) { + write(node, "implicit", implicit); + write(node, "password", password); + write(node, "clientCredentials", clientCredentials); + write(node, "authorizationCode", authorizationCode); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java new file mode 100644 index 00000000000..1a3d9650139 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.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.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.config.nested.OpenAPIConfig; +import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Constants; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Function; + +public final class OpenAPI extends Node { + + private String openapi; + private Info info; + private List servers; + private Map paths; + private Components components; + private List security; + private List tags; + private ExternalDocs externalDocs; + + private String group; + private int priority; + + private transient OpenAPIConfig globalConfig; + private transient OpenAPIConfig config; + private transient ServiceMeta meta; + + public String getOpenapi() { + return openapi; + } + + public OpenAPI setOpenapi(String openapi) { + this.openapi = openapi; + return this; + } + + public Info getInfo() { + return info; + } + + public OpenAPI setInfo(Info info) { + this.info = info; + return this; + } + + public List getServers() { + return servers; + } + + public OpenAPI setServers(List servers) { + this.servers = servers; + return this; + } + + public OpenAPI addServer(Server server) { + List thisServers = servers; + if (thisServers == null) { + servers = thisServers = new ArrayList<>(); + } else { + for (int i = 0, size = thisServers.size(); i < size; i++) { + if (thisServers.get(i).getUrl().equals(server.getUrl())) { + return this; + } + } + } + thisServers.add(server); + return this; + } + + public OpenAPI removeServer(Server server) { + if (servers != null) { + servers.remove(server); + } + return this; + } + + public Map getPaths() { + return paths; + } + + public PathItem getPath(String path) { + return paths == null ? null : paths.get(path); + } + + public PathItem getOrAddPath(String path) { + if (paths == null) { + paths = new LinkedHashMap<>(); + } + return paths.computeIfAbsent(path, k -> new PathItem()); + } + + public OpenAPI setPaths(Map paths) { + this.paths = paths; + return this; + } + + public OpenAPI addPath(String path, PathItem pathItem) { + if (paths == null) { + paths = new LinkedHashMap<>(); + } + paths.put(path, pathItem); + return this; + } + + public OpenAPI removePath(String path) { + if (paths != null) { + paths.remove(path); + } + return this; + } + + public Components getComponents() { + return components; + } + + public OpenAPI setComponents(Components components) { + this.components = components; + return this; + } + + public List getSecurity() { + return security; + } + + public OpenAPI setSecurity(List security) { + this.security = security; + return this; + } + + public OpenAPI addSecurity(SecurityRequirement securityRequirement) { + if (security == null) { + security = new ArrayList<>(); + } + security.add(securityRequirement); + return this; + } + + public List getTags() { + return tags; + } + + public OpenAPI setTags(List tags) { + this.tags = tags; + return this; + } + + public OpenAPI addTag(Tag tag) { + List thisTags = tags; + if (thisTags == null) { + tags = thisTags = new ArrayList<>(); + } else { + for (int i = 0, size = thisTags.size(); i < size; i++) { + if (thisTags.get(i).getName().equals(tag.getName())) { + return this; + } + } + } + thisTags.add(tag); + return this; + } + + public OpenAPI removeTag(Tag tag) { + if (tags != null) { + tags.remove(tag); + } + return this; + } + + public ExternalDocs getExternalDocs() { + return externalDocs; + } + + public OpenAPI setExternalDocs(ExternalDocs externalDocs) { + this.externalDocs = externalDocs; + return this; + } + + public String getGroup() { + return group; + } + + public OpenAPI setGroup(String group) { + this.group = group; + return this; + } + + public int getPriority() { + return priority; + } + + public OpenAPI setPriority(int priority) { + this.priority = priority; + return this; + } + + public OpenAPIConfig getGlobalConfig() { + return globalConfig; + } + + public OpenAPI setGlobalConfig(OpenAPIConfig globalConfig) { + this.globalConfig = globalConfig; + return this; + } + + public OpenAPIConfig getConfig() { + return config; + } + + public OpenAPI setConfig(OpenAPIConfig config) { + this.config = config; + return this; + } + + public T getConfigValue(Function fn) { + if (config != null) { + T value = fn.apply(config); + if (value != null) { + return value; + } + } + return globalConfig == null ? null : fn.apply(globalConfig); + } + + public String getConfigSetting(String key) { + return getConfigValue(config -> config == null ? null : config.getSetting(key)); + } + + public void walkOperations(Consumer consumer) { + Map paths = this.paths; + if (paths == null) { + return; + } + + for (PathItem pathItem : paths.values()) { + Map operations = pathItem.getOperations(); + if (operations != null) { + for (Operation operation : operations.values()) { + consumer.accept(operation); + } + } + } + } + + public ServiceMeta getMeta() { + return meta; + } + + public OpenAPI setMeta(ServiceMeta meta) { + this.meta = meta; + return this; + } + + @Override + public OpenAPI clone() { + OpenAPI clone = super.clone(); + clone.info = clone(info); + clone.servers = clone(servers); + clone.paths = clone(paths); + clone.components = clone(components); + clone.security = clone(security); + clone.tags = clone(tags); + clone.externalDocs = clone(externalDocs); + return clone; + } + + @Override + public Map writeTo(Map node, Context context) { + node.put("openapi", openapi == null ? Constants.VERSION_30 : openapi); + write(node, "info", info, context); + write(node, "servers", servers, context); + write(node, "paths", paths, context); + write(node, "components", components, context); + write(node, "security", security, context); + write(node, "tags", tags, context); + write(node, "externalDocs", externalDocs, context); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java new file mode 100644 index 00000000000..b4d394d3b4a --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java @@ -0,0 +1,320 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Constants; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter.In; +import org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public final class Operation extends Node { + + private Set tags; + private String summary; + private String description; + private ExternalDocs externalDocs; + private String operationId; + private List parameters; + private RequestBody requestBody; + private Map responses; + private Boolean deprecated; + private List security; + private List servers; + + private String group; + private String version; + private HttpMethods httpMethod; + private transient MethodMeta meta; + + public Set getTags() { + return tags; + } + + public Operation setTags(Set tags) { + this.tags = tags; + return this; + } + + public Operation addTag(String tag) { + if (tags == null) { + tags = new LinkedHashSet<>(); + } + tags.add(tag); + return this; + } + + public Operation removeTag(String tag) { + if (tags != null) { + tags.remove(tag); + } + return this; + } + + public String getSummary() { + return summary; + } + + public Operation setSummary(String summary) { + this.summary = summary; + return this; + } + + public String getDescription() { + return description; + } + + public Operation setDescription(String description) { + this.description = description; + return this; + } + + public ExternalDocs getExternalDocs() { + return externalDocs; + } + + public Operation setExternalDocs(ExternalDocs externalDocs) { + this.externalDocs = externalDocs; + return this; + } + + public String getOperationId() { + return operationId; + } + + public Operation setOperationId(String operationId) { + this.operationId = operationId; + return this; + } + + public List getParameters() { + return parameters; + } + + public Parameter getParameter(String name, In in) { + if (parameters == null || name == null || in == null) { + return null; + } + for (int i = 0, size = parameters.size(); i < size; i++) { + Parameter parameter = parameters.get(i); + if (name.equals(parameter.getName()) && in == parameter.getIn()) { + return parameter; + } + } + return null; + } + + public Operation setParameters(List parameters) { + this.parameters = parameters; + return this; + } + + public Operation addParameter(Parameter parameter) { + if (parameters == null) { + parameters = new ArrayList<>(); + } + parameters.add(parameter); + return this; + } + + public Operation removeParameter(Parameter parameter) { + if (parameters != null) { + parameters.remove(parameter); + } + return this; + } + + public RequestBody getRequestBody() { + return requestBody; + } + + public Operation setRequestBody(RequestBody requestBody) { + this.requestBody = requestBody; + return this; + } + + public Map getResponses() { + return responses; + } + + public ApiResponse getResponse(String httpStatusCode) { + return responses == null ? null : responses.get(httpStatusCode); + } + + public ApiResponse getOrAddResponse(String httpStatusCode) { + if (responses == null) { + responses = new LinkedHashMap<>(); + } + return responses.computeIfAbsent(httpStatusCode, k -> new ApiResponse()); + } + + public Operation setResponses(Map responses) { + this.responses = responses; + return this; + } + + public Operation addResponse(String name, ApiResponse response) { + if (responses == null) { + responses = new LinkedHashMap<>(); + } + responses.put(name, response); + return this; + } + + public Operation removeResponse(String name) { + if (responses != null) { + responses.remove(name); + } + return this; + } + + public Boolean getDeprecated() { + return deprecated; + } + + public Operation setDeprecated(Boolean deprecated) { + this.deprecated = deprecated; + return this; + } + + public List getSecurity() { + return security; + } + + public Operation setSecurity(List security) { + this.security = security; + return this; + } + + public Operation addSecurity(SecurityRequirement security) { + if (this.security == null) { + this.security = new ArrayList<>(); + } + this.security.add(security); + return this; + } + + public Operation removeSecurity(SecurityRequirement security) { + if (this.security != null) { + this.security.remove(security); + } + return this; + } + + public List getServers() { + return servers; + } + + public Operation setServers(List servers) { + this.servers = servers; + return this; + } + + public Operation addServer(Server server) { + if (servers == null) { + servers = new ArrayList<>(); + } + servers.add(server); + return this; + } + + public Operation removeServer(Server server) { + if (servers != null) { + servers.remove(server); + } + return this; + } + + public String getGroup() { + return group; + } + + public Operation setGroup(String group) { + this.group = group; + return this; + } + + public String getVersion() { + return version; + } + + public Operation setVersion(String version) { + this.version = version; + return this; + } + + public HttpMethods getHttpMethod() { + return httpMethod; + } + + public Operation setHttpMethod(HttpMethods httpMethod) { + this.httpMethod = httpMethod; + return this; + } + + public MethodMeta getMeta() { + return meta; + } + + public Operation setMeta(MethodMeta meta) { + this.meta = meta; + return this; + } + + @Override + public Operation clone() { + Operation clone = super.clone(); + if (tags != null) { + clone.tags = new LinkedHashSet<>(tags); + } + clone.externalDocs = clone(externalDocs); + clone.parameters = clone(parameters); + clone.requestBody = clone(requestBody); + clone.responses = clone(responses); + clone.security = clone(security); + clone.servers = clone(servers); + return clone; + } + + @Override + public Map writeTo(Map node, Context context) { + write(node, "tags", tags); + write(node, "summary", summary); + write(node, "description", description); + write(node, "externalDocs", externalDocs, context); + write(node, "operationId", operationId); + write(node, "parameters", parameters, context); + write(node, "requestBody", requestBody, context); + write(node, "responses", responses, context); + write(node, "deprecated", deprecated); + write(node, "security", security, context); + write(node, "servers", servers, context); + writeExtensions(node); + write(node, Constants.X_JAVA_CLASS, meta.getServiceMeta().getServiceInterface()); + write(node, Constants.X_JAVA_METHOD, meta.getMethod().getName()); + write(node, Constants.X_JAVA_METHOD_DESCRIPTOR, TypeUtils.getMethodDescriptor(meta)); + return node; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java new file mode 100644 index 00000000000..0179dc54381 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java @@ -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. + */ +package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Objects; + +public final class Parameter extends Node { + + public enum In { + PATH("path"), + QUERY("query"), + HEADER("header"), + COOKIE("cookie"); + + private final String value; + + In(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + + public enum Style { + MATRIX("matrix"), + LABEL("label"), + FORM("form"), + SIMPLE("simple"), + SPACE_DELIMITED("spaceDelimited"), + PIPE_DELIMITED("pipeDelimited"), + DEEP_OBJECT("deepObject"); + + private final String value; + + Style(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + + private final String name; + private final In in; + private String description; + private Boolean required; + private Boolean deprecated; + private Boolean allowEmptyValue; + private Style style; + private Boolean explode; + private Boolean allowReserved; + private Schema schema; + private Object example; + private Map examples; + private Map contents; + + private transient ParameterMeta meta; + + public Parameter(String name, In in) { + this.name = Objects.requireNonNull(name); + this.in = Objects.requireNonNull(in); + } + + public String getName() { + return name; + } + + public In getIn() { + return in; + } + + public String getDescription() { + return description; + } + + public Parameter setDescription(String description) { + this.description = description; + return this; + } + + public Boolean getRequired() { + return required; + } + + public Parameter setRequired(Boolean required) { + this.required = required; + return this; + } + + public Boolean getDeprecated() { + return deprecated; + } + + public Parameter setDeprecated(Boolean deprecated) { + this.deprecated = deprecated; + return this; + } + + public Boolean getAllowEmptyValue() { + return allowEmptyValue; + } + + public Parameter setAllowEmptyValue(Boolean allowEmptyValue) { + this.allowEmptyValue = allowEmptyValue; + return this; + } + + public Style getStyle() { + return style; + } + + public Parameter setStyle(Style style) { + this.style = style; + return this; + } + + public Boolean getExplode() { + return explode; + } + + public Parameter setExplode(Boolean explode) { + this.explode = explode; + return this; + } + + public Boolean getAllowReserved() { + return allowReserved; + } + + public Parameter setAllowReserved(Boolean allowReserved) { + this.allowReserved = allowReserved; + return this; + } + + public Schema getSchema() { + return schema; + } + + public Parameter setSchema(Schema schema) { + this.schema = schema; + return this; + } + + public Object getExample() { + return example; + } + + public Parameter setExample(Object example) { + this.example = example; + return this; + } + + public Map getExamples() { + return examples; + } + + public Parameter setExamples(Map examples) { + this.examples = examples; + return this; + } + + public Parameter addExample(String name, Example example) { + if (examples == null) { + examples = new LinkedHashMap<>(); + } + examples.put(name, example); + return this; + } + + public Parameter removeExample(String name) { + if (examples != null) { + examples.remove(name); + } + return this; + } + + public Map getContents() { + return contents; + } + + public Parameter setContents(Map contents) { + this.contents = contents; + return this; + } + + public Parameter addContent(String name, MediaType content) { + if (contents == null) { + contents = new LinkedHashMap<>(); + } + contents.put(name, content); + return this; + } + + public Parameter removeContent(String name) { + if (contents != null) { + contents.remove(name); + } + return this; + } + + public ParameterMeta getMeta() { + return meta; + } + + public Parameter setMeta(ParameterMeta meta) { + this.meta = meta; + return this; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || obj.getClass() != Parameter.class) { + return false; + } + Parameter other = (Parameter) obj; + return name.equals(other.name) && in == other.in; + } + + @Override + public int hashCode() { + return 31 * name.hashCode() + in.hashCode(); + } + + @Override + public Parameter clone() { + Parameter clone = super.clone(); + clone.schema = clone(schema); + clone.examples = clone(examples); + clone.contents = clone(contents); + return clone; + } + + @Override + public Map writeTo(Map node, Context context) { + write(node, "name", name); + write(node, "in", in.toString()); + write(node, "description", description); + write(node, "required", required); + write(node, "deprecated", deprecated); + write(node, "allowEmptyValue", allowEmptyValue); + write(node, "style", style); + write(node, "explode", explode); + write(node, "allowReserved", allowReserved); + write(node, "schema", schema, context); + write(node, "example", example); + write(node, "examples", examples, context); + write(node, "content", contents, context); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java new file mode 100644 index 00000000000..eaff4f0ca93 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.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.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public final class PathItem extends Node { + + private String ref; + private String summary; + private String description; + private Map operations; + private List servers; + private List parameters; + + public String getRef() { + return ref; + } + + public PathItem setRef(String ref) { + this.ref = ref; + return this; + } + + public String getSummary() { + return summary; + } + + public PathItem setSummary(String summary) { + this.summary = summary; + return this; + } + + public String getDescription() { + return description; + } + + public PathItem setDescription(String description) { + this.description = description; + return this; + } + + public Map getOperations() { + return operations; + } + + public Operation getOperation(HttpMethods method) { + return operations == null ? null : operations.get(method); + } + + public PathItem setOperations(Map operations) { + this.operations = operations; + return this; + } + + public PathItem addOperation(HttpMethods method, Operation operation) { + if (operations == null) { + operations = new LinkedHashMap<>(); + } + operations.put(method, operation); + return this; + } + + public PathItem removeOperation(HttpMethods method) { + if (operations != null) { + operations.remove(method); + } + return this; + } + + public List getServers() { + return servers; + } + + public PathItem setServers(List servers) { + this.servers = servers; + return this; + } + + public PathItem addServer(Server server) { + if (servers == null) { + servers = new ArrayList<>(); + } + servers.add(server); + return this; + } + + public PathItem removeServer(Server server) { + if (servers != null) { + servers.remove(server); + } + return this; + } + + public List getParameters() { + return parameters; + } + + public PathItem setParameters(List parameters) { + this.parameters = parameters; + return this; + } + + public PathItem addParameter(Parameter parameter) { + List thisParameters = parameters; + if (thisParameters == null) { + parameters = thisParameters = new ArrayList<>(); + } else { + for (int i = 0, size = thisParameters.size(); i < size; i++) { + Parameter tParameter = thisParameters.get(i); + if (tParameter.getName().equals(parameter.getName())) { + return this; + } + } + } + thisParameters.add(parameter); + return this; + } + + public PathItem removeParameter(Parameter parameter) { + if (parameters != null) { + parameters.remove(parameter); + } + return this; + } + + @Override + public PathItem clone() { + PathItem clone = super.clone(); + clone.operations = clone(operations); + clone.servers = clone(servers); + clone.parameters = clone(parameters); + return clone; + } + + @Override + public Map writeTo(Map node, Context context) { + if (ref != null) { + write(node, "$ref", Helper.pathToRef(ref)); + } else if (operations != null) { + write(node, "summary", summary); + write(node, "description", description); + for (Map.Entry entry : operations.entrySet()) { + write(node, entry.getKey().name().toLowerCase(), entry.getValue(), context); + } + write(node, "servers", servers, context); + write(node, "parameters", parameters, context); + } + writeExtensions(node); + return node; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/RequestBody.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/RequestBody.java new file mode 100644 index 00000000000..eb3e21165ad --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/RequestBody.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.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; + +import java.util.LinkedHashMap; +import java.util.Map; + +public final class RequestBody extends Node { + + private String description; + private Map contents; + private boolean required; + + public String getDescription() { + return description; + } + + public RequestBody setDescription(String description) { + this.description = description; + return this; + } + + public Map getContents() { + return contents; + } + + public MediaType getContent(String content) { + return contents == null ? null : contents.get(content); + } + + public MediaType getOrAddContent(String content) { + if (contents == null) { + contents = new LinkedHashMap<>(); + } + return contents.computeIfAbsent(content, k -> new MediaType()); + } + + public RequestBody setContents(Map contents) { + this.contents = contents; + return this; + } + + public RequestBody addContent(String name, MediaType content) { + if (contents == null) { + contents = new LinkedHashMap<>(); + } + contents.put(name, content); + return this; + } + + public RequestBody removeContent(String name) { + if (contents != null) { + contents.remove(name); + } + return this; + } + + public boolean isRequired() { + return required; + } + + public RequestBody setRequired(boolean required) { + this.required = required; + return this; + } + + @Override + public RequestBody clone() { + RequestBody clone = super.clone(); + clone.contents = clone(contents); + return clone; + } + + @Override + public Map writeTo(Map node, Context context) { + write(node, "description", description); + write(node, "required", required); + write(node, "content", contents, context); + return node; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java new file mode 100644 index 00000000000..62ae7184428 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java @@ -0,0 +1,639 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Constants; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public final class Schema extends Node { + + public enum Type { + STRING("string"), + INTEGER("integer"), + NUMBER("number"), + BOOLEAN("boolean"), + OBJECT("object"), + ARRAY("array"); + + private final String value; + + Type(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + + public Type of(String value) { + for (Type type : values()) { + if (type.value.equals(value)) { + return type; + } + } + return STRING; + } + } + + private String ref; + private String format; + private String name; + private String title; + private String description; + private Object defaultValue; + private BigDecimal multipleOf; + private BigDecimal maximum; + private Boolean exclusiveMaximum; + private BigDecimal minimum; + private Boolean exclusiveMinimum; + private Integer maxLength; + private Integer minLength; + private String pattern; + private Integer maxItems; + private Integer minItems; + private Boolean uniqueItems; + private Integer maxProperties; + private Integer minProperties; + private Boolean required; + private List enumeration; + private Type type; + private Schema items; + private Map properties; + private Schema additionalPropertiesSchema; + private Boolean additionalPropertiesBoolean; + private Boolean readOnly; + private XML xml; + private ExternalDocs externalDocs; + private Object example; + private List allOf; + private List oneOf; + private List anyOf; + private Schema not; + private Discriminator discriminator; + private Boolean nullable; + private Boolean writeOnly; + private Boolean deprecated; + + private String group; + private String version; + private Class javaType; + private transient Schema targetSchema; + private transient List sourceSchemas; + + public String getRef() { + return ref; + } + + public Schema setRef(String ref) { + this.ref = ref; + return this; + } + + public String getFormat() { + return format; + } + + public Schema setFormat(String format) { + this.format = format; + return this; + } + + public String getName() { + return name; + } + + public Schema setName(String name) { + this.name = name; + return this; + } + + public String getTitle() { + return title; + } + + public Schema setTitle(String title) { + this.title = title; + return this; + } + + public String getDescription() { + return description; + } + + public Schema setDescription(String description) { + this.description = description; + return this; + } + + public Object getDefaultValue() { + return defaultValue; + } + + public Schema setDefaultValue(Object defaultValue) { + this.defaultValue = defaultValue; + return this; + } + + public BigDecimal getMultipleOf() { + return multipleOf; + } + + public Schema setMultipleOf(BigDecimal multipleOf) { + this.multipleOf = multipleOf; + return this; + } + + public BigDecimal getMaximum() { + return maximum; + } + + public Schema setMaximum(BigDecimal maximum) { + this.maximum = maximum; + return this; + } + + public Boolean getExclusiveMaximum() { + return exclusiveMaximum; + } + + public Schema setExclusiveMaximum(Boolean exclusiveMaximum) { + this.exclusiveMaximum = exclusiveMaximum; + return this; + } + + public BigDecimal getMinimum() { + return minimum; + } + + public Schema setMinimum(BigDecimal minimum) { + this.minimum = minimum; + return this; + } + + public Boolean getExclusiveMinimum() { + return exclusiveMinimum; + } + + public Schema setExclusiveMinimum(Boolean exclusiveMinimum) { + this.exclusiveMinimum = exclusiveMinimum; + return this; + } + + public Integer getMaxLength() { + return maxLength; + } + + public Schema setMaxLength(Integer maxLength) { + this.maxLength = maxLength; + return this; + } + + public Integer getMinLength() { + return minLength; + } + + public Schema setMinLength(Integer minLength) { + this.minLength = minLength; + return this; + } + + public String getPattern() { + return pattern; + } + + public Schema setPattern(String pattern) { + this.pattern = pattern; + return this; + } + + public Integer getMaxItems() { + return maxItems; + } + + public Schema setMaxItems(Integer maxItems) { + this.maxItems = maxItems; + return this; + } + + public Integer getMinItems() { + return minItems; + } + + public Schema setMinItems(Integer minItems) { + this.minItems = minItems; + return this; + } + + public Boolean getUniqueItems() { + return uniqueItems; + } + + public Schema setUniqueItems(Boolean uniqueItems) { + this.uniqueItems = uniqueItems; + return this; + } + + public Integer getMaxProperties() { + return maxProperties; + } + + public Schema setMaxProperties(Integer maxProperties) { + this.maxProperties = maxProperties; + return this; + } + + public Integer getMinProperties() { + return minProperties; + } + + public Schema setMinProperties(Integer minProperties) { + this.minProperties = minProperties; + return this; + } + + public Boolean getRequired() { + return required; + } + + public Schema setRequired(Boolean required) { + this.required = required; + return this; + } + + public List getEnumeration() { + return enumeration; + } + + public Schema setEnumeration(List enumeration) { + this.enumeration = enumeration; + return this; + } + + public Schema addEnumeration(Object enumeration) { + if (this.enumeration == null) { + this.enumeration = new ArrayList<>(); + } + this.enumeration.add(enumeration); + return this; + } + + public Schema removeEnumeration(Object enumeration) { + if (this.enumeration != null) { + this.enumeration.remove(enumeration); + } + return this; + } + + public Type getType() { + return type; + } + + public Schema setType(Type type) { + this.type = type; + return this; + } + + public Schema getItems() { + return items; + } + + public Schema setItems(Schema items) { + this.items = items; + return this; + } + + public Map getProperties() { + return properties; + } + + public Schema getProperty(String name) { + return properties == null ? null : properties.get(name); + } + + public Schema setProperties(Map properties) { + this.properties = properties; + return this; + } + + public Schema addProperty(String name, Schema schema) { + if (schema == null) { + return this; + } + if (properties == null) { + properties = new LinkedHashMap<>(); + } + properties.put(name, schema); + return this; + } + + public Schema removeProperty(String name) { + if (properties != null) { + properties.remove(name); + } + return this; + } + + public Schema getAdditionalPropertiesSchema() { + return additionalPropertiesSchema; + } + + public Schema setAdditionalPropertiesSchema(Schema additionalPropertiesSchema) { + this.additionalPropertiesSchema = additionalPropertiesSchema; + return this; + } + + public Boolean getAdditionalPropertiesBoolean() { + return additionalPropertiesBoolean; + } + + public Schema setAdditionalPropertiesBoolean(Boolean additionalPropertiesBoolean) { + this.additionalPropertiesBoolean = additionalPropertiesBoolean; + return this; + } + + public Boolean getReadOnly() { + return readOnly; + } + + public Schema setReadOnly(Boolean readOnly) { + this.readOnly = readOnly; + return this; + } + + public XML getXml() { + return xml; + } + + public Schema setXml(XML xml) { + this.xml = xml; + return this; + } + + public ExternalDocs getExternalDocs() { + return externalDocs; + } + + public Schema setExternalDocs(ExternalDocs externalDocs) { + this.externalDocs = externalDocs; + return this; + } + + public Object getExample() { + return example; + } + + public Schema setExample(Object example) { + this.example = example; + return this; + } + + public List getAllOf() { + return allOf; + } + + public Schema setAllOf(List allOf) { + this.allOf = allOf; + return this; + } + + public Schema addAllOf(Schema schema) { + if (allOf == null) { + allOf = new ArrayList<>(); + } + allOf.add(schema); + return this; + } + + public List getOneOf() { + return oneOf; + } + + public Schema setOneOf(List oneOf) { + this.oneOf = oneOf; + return this; + } + + public Schema addOneOf(Schema schema) { + if (oneOf == null) { + oneOf = new ArrayList<>(); + } + oneOf.add(schema); + return this; + } + + public List getAnyOf() { + return anyOf; + } + + public Schema setAnyOf(List anyOf) { + this.anyOf = anyOf; + return this; + } + + public Schema addAnyOf(Schema schema) { + if (anyOf == null) { + anyOf = new ArrayList<>(); + } + anyOf.add(schema); + return this; + } + + public Schema getNot() { + return not; + } + + public Schema setNot(Schema not) { + this.not = not; + return this; + } + + public Discriminator getDiscriminator() { + return discriminator; + } + + public Schema setDiscriminator(Discriminator discriminator) { + this.discriminator = discriminator; + return this; + } + + public Boolean getNullable() { + return nullable; + } + + public Schema setNullable(Boolean nullable) { + this.nullable = nullable; + return this; + } + + public Boolean getWriteOnly() { + return writeOnly; + } + + public Schema setWriteOnly(Boolean writeOnly) { + this.writeOnly = writeOnly; + return this; + } + + public Boolean getDeprecated() { + return deprecated; + } + + public Schema setDeprecated(Boolean deprecated) { + this.deprecated = deprecated; + return this; + } + + public String getGroup() { + return group; + } + + public Schema setGroup(String group) { + this.group = group; + return this; + } + + public String getVersion() { + return version; + } + + public Schema setVersion(String version) { + this.version = version; + return this; + } + + public Class getJavaType() { + return javaType; + } + + public Schema setJavaType(Class javaType) { + this.javaType = javaType; + return this; + } + + public Schema getTargetSchema() { + return targetSchema; + } + + public Schema setTargetSchema(Schema targetSchema) { + this.targetSchema = targetSchema; + return this; + } + + public List getSourceSchemas() { + return sourceSchemas; + } + + public Schema setSourceSchemas(List sourceSchemas) { + this.sourceSchemas = sourceSchemas; + return this; + } + + public void addSourceSchema(Schema sourceSchema) { + if (sourceSchemas == null) { + sourceSchemas = new LinkedList<>(); + } + sourceSchemas.add(sourceSchema); + } + + @Override + public Schema clone() { + Schema clone = super.clone(); + if (enumeration != null) { + clone.enumeration = new ArrayList<>(enumeration); + } + clone.items = clone(items); + clone.properties = clone(properties); + clone.additionalPropertiesSchema = clone(additionalPropertiesSchema); + clone.xml = clone(xml); + clone.externalDocs = clone(externalDocs); + clone.allOf = clone(allOf); + clone.oneOf = clone(oneOf); + clone.anyOf = clone(anyOf); + clone.not = clone(not); + clone.discriminator = clone(discriminator); + return clone; + } + + @Override + public Map writeTo(Map schema, Context context) { + if (ref != null) { + schema.put("$ref", ref); + } + write(schema, "format", format); + write(schema, "title", title); + write(schema, "description", description); + write(schema, "default", defaultValue); + write(schema, "multipleOf", multipleOf); + write(schema, "maximum", maximum); + write(schema, "exclusiveMaximum", exclusiveMaximum); + write(schema, "minimum", minimum); + write(schema, "exclusiveMinimum", exclusiveMinimum); + write(schema, "maxLength", maxLength); + write(schema, "minLength", minLength); + write(schema, "pattern", pattern); + write(schema, "maxItems", maxItems); + write(schema, "minItems", minItems); + write(schema, "uniqueItems", uniqueItems); + write(schema, "maxProperties", maxProperties); + write(schema, "minProperties", minProperties); + write(schema, "required", required); + write(schema, "enum", enumeration); + if (type != null) { + if (context.isOpenAPI31()) { + if (nullable == null || !nullable) { + write(schema, "type", type.toString()); + } else { + write(schema, "type", new String[] {type.toString(), "null"}); + } + } else { + write(schema, "type", type.toString()); + write(schema, "nullable", nullable); + } + } + write(schema, "items", items, context); + write(schema, "properties", properties, context); + if (additionalPropertiesBoolean == null) { + write(schema, "additionalProperties", additionalPropertiesSchema, context); + } else { + schema.put("additionalProperties", additionalPropertiesBoolean); + } + write(schema, "readOnly", readOnly); + write(schema, "xml", xml, context); + write(schema, "externalDocs", externalDocs, context); + write(schema, "example", example); + write(schema, "allOf", allOf, context); + write(schema, "oneOf", oneOf, context); + write(schema, "anyOf", anyOf, context); + write(schema, "not", not, context); + write(schema, "discriminator", discriminator, context); + write(schema, "writeOnly", writeOnly); + write(schema, "deprecated", deprecated); + writeExtensions(schema); + if (javaType != null) { + schema.put(Constants.X_JAVA_CLASS, javaType.getName()); + } + return schema; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityRequirement.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityRequirement.java new file mode 100644 index 00000000000..bea8a691fac --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityRequirement.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.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public final class SecurityRequirement extends Node { + + private Map> requirements; + + public Map> getRequirements() { + return requirements; + } + + public void setRequirements(Map> requirements) { + this.requirements = requirements; + } + + public SecurityRequirement addRequirement(String name, String... scope) { + return addRequirement(name, scope == null ? Collections.emptyList() : Arrays.asList(scope)); + } + + public SecurityRequirement addRequirement(String name, List scopes) { + if (requirements == null) { + requirements = new LinkedHashMap<>(); + } + if (scopes == null) { + scopes = Collections.emptyList(); + } + requirements.put(name, scopes); + return this; + } + + public void removeRequirement(String name) { + if (requirements != null) { + requirements.remove(name); + } + } + + @Override + public SecurityRequirement clone() { + SecurityRequirement clone = super.clone(); + if (requirements != null) { + Map> requirements = newMap(this.requirements.size()); + for (Map.Entry> entry : this.requirements.entrySet()) { + requirements.put(entry.getKey(), new ArrayList<>(entry.getValue())); + } + clone.requirements = requirements; + } + return clone; + } + + @Override + public Map writeTo(Map node, Context context) { + write(node, "requirements", requirements); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityScheme.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityScheme.java new file mode 100644 index 00000000000..74e297878eb --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityScheme.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.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; + +import java.util.Map; + +public final class SecurityScheme extends Node { + + public enum Type { + APIKEY("apiKey"), + HTTP("http"), + OAUTH2("oauth2"), + MUTUAL_TLS("mutualTLS"), + OPEN_ID_CONNECT("openIdConnect"); + + private final String value; + + Type(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + + public enum In { + COOKIE("cookie"), + HEADER("header"), + QUERY("query"); + + private final String value; + + In(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + + private Type type; + private String description; + private String name; + private In in; + private String scheme; + private String bearerFormat; + private OAuthFlows flows; + private String openIdConnectUrl; + + public Type getType() { + return type; + } + + public SecurityScheme setType(Type type) { + this.type = type; + return this; + } + + public String getDescription() { + return description; + } + + public SecurityScheme setDescription(String description) { + this.description = description; + return this; + } + + public String getName() { + return name; + } + + public SecurityScheme setName(String name) { + this.name = name; + return this; + } + + public In getIn() { + return in; + } + + public SecurityScheme setIn(In in) { + this.in = in; + return this; + } + + public String getScheme() { + return scheme; + } + + public SecurityScheme setScheme(String scheme) { + this.scheme = scheme; + return this; + } + + public String getBearerFormat() { + return bearerFormat; + } + + public SecurityScheme setBearerFormat(String bearerFormat) { + this.bearerFormat = bearerFormat; + return this; + } + + public OAuthFlows getFlows() { + return flows; + } + + public SecurityScheme setFlows(OAuthFlows flows) { + this.flows = flows; + return this; + } + + public String getOpenIdConnectUrl() { + return openIdConnectUrl; + } + + public SecurityScheme setOpenIdConnectUrl(String openIdConnectUrl) { + this.openIdConnectUrl = openIdConnectUrl; + return this; + } + + @Override + public SecurityScheme clone() { + SecurityScheme clone = super.clone(); + clone.flows = clone(flows); + return clone; + } + + @Override + public Map writeTo(Map node, Context context) { + if (type == null) { + return node; + } + write(node, "type", type.toString()); + write(node, "description", description); + write(node, "name", name); + if (in != null) { + write(node, "in", in.toString()); + } + write(node, "scheme", scheme); + write(node, "bearerFormat", bearerFormat); + write(node, "flows", flows, context); + write(node, "openIdConnectUrl", openIdConnectUrl); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Server.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Server.java new file mode 100644 index 00000000000..4b3c978f2fb --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Server.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.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; + +import java.util.LinkedHashMap; +import java.util.Map; + +public final class Server extends Node { + + private String url; + private String description; + private Map variables; + + public String getUrl() { + return url; + } + + public Server setUrl(String url) { + this.url = url; + return this; + } + + public String getDescription() { + return description; + } + + public Server setDescription(String description) { + this.description = description; + return this; + } + + public Map getVariables() { + return variables; + } + + public Server setVariables(Map variables) { + this.variables = variables; + return this; + } + + public Server addVariable(String name, ServerVariable variable) { + if (variables == null) { + variables = new LinkedHashMap<>(); + } + variables.put(name, variable); + return this; + } + + public Server removeVariable(String name) { + if (variables != null) { + variables.remove(name); + } + return this; + } + + @Override + public Server clone() { + Server clone = super.clone(); + clone.variables = clone(variables); + return clone; + } + + @Override + public Map writeTo(Map node, Context context) { + write(node, "url", url); + write(node, "description", description); + write(node, "variables", variables, context); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ServerVariable.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ServerVariable.java new file mode 100644 index 00000000000..b3977c50482 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ServerVariable.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.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public final class ServerVariable extends Node { + + private List enumeration; + private String defaultValue; + private String description; + + public List getEnumeration() { + return enumeration; + } + + public ServerVariable setEnumeration(List enumeration) { + this.enumeration = enumeration; + return this; + } + + public ServerVariable addEnumeration(String value) { + if (enumeration == null) { + enumeration = new ArrayList<>(); + } + enumeration.add(value); + return this; + } + + public ServerVariable removeEnumeration(String value) { + if (enumeration != null) { + enumeration.remove(value); + } + return this; + } + + public String getDefaultValue() { + return defaultValue; + } + + public ServerVariable setDefaultValue(String defaultValue) { + this.defaultValue = defaultValue; + return this; + } + + public String getDescription() { + return description; + } + + public ServerVariable setDescription(String description) { + this.description = description; + return this; + } + + @Override + public ServerVariable clone() { + ServerVariable clone = super.clone(); + if (enumeration != null) { + clone.enumeration = new ArrayList<>(enumeration); + } + return clone; + } + + @Override + public Map writeTo(Map node, Context context) { + write(node, "enum", enumeration); + write(node, "default", defaultValue); + write(node, "description", description); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Tag.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Tag.java new file mode 100644 index 00000000000..11820f7b825 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Tag.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.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; + +import java.util.Map; + +public final class Tag extends Node { + + private String name; + private String description; + private ExternalDocs externalDocs; + + public String getName() { + return name; + } + + public Tag setName(String name) { + this.name = name; + return this; + } + + public String getDescription() { + return description; + } + + public Tag setDescription(String description) { + this.description = description; + return this; + } + + public ExternalDocs getExternalDocs() { + return externalDocs; + } + + public Tag setExternalDocs(ExternalDocs externalDocs) { + this.externalDocs = externalDocs; + return this; + } + + @Override + public Tag clone() { + Tag clone = super.clone(); + clone.externalDocs = clone(externalDocs); + return clone; + } + + @Override + public Map writeTo(Map node, Context context) { + node.put("name", name); + node.put("description", description); + write(node, "externalDocs", externalDocs, context); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/XML.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/XML.java new file mode 100644 index 00000000000..20ab6a44b5f --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/XML.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.dubbo.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; + +import java.util.Map; + +public final class XML extends Node { + + private String name; + private String namespace; + private String prefix; + private Boolean attribute; + private Boolean wrapped; + + public String getName() { + return name; + } + + public XML setName(String name) { + this.name = name; + return this; + } + + public String getNamespace() { + return namespace; + } + + public XML setNamespace(String namespace) { + this.namespace = namespace; + return this; + } + + public String getPrefix() { + return prefix; + } + + public XML setPrefix(String prefix) { + this.prefix = prefix; + return this; + } + + public Boolean getAttribute() { + return attribute; + } + + public XML setAttribute(Boolean attribute) { + this.attribute = attribute; + return this; + } + + public Boolean getWrapped() { + return wrapped; + } + + public XML setWrapped(Boolean wrapped) { + this.wrapped = wrapped; + return this; + } + + @Override + public Map writeTo(Map node, Context context) { + node.put("name", name); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java new file mode 100644 index 00000000000..7afa1326992 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.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.dubbo.rpc.protocol.tri.rest.support.basic; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.PropertyMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIDefinitionResolver; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaPredicate; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ExternalDocs; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Info; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema.Type; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Tag; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Map; + +import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.setBoolValue; +import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.setValue; +import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.trim; + +@Activate(order = 100) +public final class BasicOpenAPIDefinitionResolver + implements OpenAPIDefinitionResolver, OpenAPISchemaResolver, OpenAPISchemaPredicate { + + private static final String HIDDEN = "hidden"; + + @Override + public OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta, OpenAPIChain chain) { + AnnotationMeta annoMeta = serviceMeta.findAnnotation(Annotations.OpenAPI); + if (annoMeta == null) { + return chain.resolve(openAPI, serviceMeta); + } + if (annoMeta.getBoolean(HIDDEN)) { + return null; + } + + Info info = openAPI.getInfo(); + if (info == null) { + openAPI.setInfo(info = new Info()); + } + + Map tags = Helper.toProperties(annoMeta.getStringArray("tags")); + for (Map.Entry entry : tags.entrySet()) { + openAPI.addTag(new Tag().setName(entry.getKey()).setDescription(entry.getValue())); + } + + String group = trim(annoMeta.getString("group")); + if (group != null) { + openAPI.setGroup(group); + } + + String title = trim(annoMeta.getString("infoTitle")); + if (title != null) { + info.setTitle(title); + } + String description = trim(annoMeta.getString("infoDescription")); + if (description != null) { + info.setDescription(description); + } + String version = trim(annoMeta.getString("infoVersion")); + if (version != null) { + info.setVersion(version); + } + + String docDescription = trim(annoMeta.getString("docDescription")); + String docUrl = trim(annoMeta.getString("docUrl")); + if (docDescription != null || docUrl != null) { + openAPI.setExternalDocs( + new ExternalDocs().setDescription(docDescription).setUrl(docUrl)); + } + + openAPI.setPriority(annoMeta.getNumber("order")); + openAPI.setExtensions(Helper.toProperties(annoMeta.getStringArray("extensions"))); + + return chain.resolve(openAPI, serviceMeta); + } + + @Override + public Collection resolve(PathItem pathItem, MethodMeta methodMeta, OperationContext context) { + AnnotationMeta annoMeta = methodMeta.findAnnotation(Annotations.Operation); + if (annoMeta == null) { + return null; + } + String method = trim(annoMeta.getString("method")); + if (method == null) { + return null; + } + return Collections.singletonList(HttpMethods.of(method.toUpperCase())); + } + + @Override + public Operation resolve(Operation operation, MethodMeta methodMeta, OperationContext ctx, OperationChain chain) { + AnnotationMeta annoMeta = methodMeta.findAnnotation(Annotations.Operation); + if (annoMeta == null) { + return chain.resolve(operation, methodMeta, ctx); + } + if (annoMeta.getBoolean(HIDDEN)) { + return null; + } + + String[] tags = trim(annoMeta.getStringArray("tags")); + if (tags != null) { + operation.setTags(new LinkedHashSet<>(Arrays.asList(tags))); + } + + String summary = trim(annoMeta.getValue()); + if (summary == null) { + summary = trim(annoMeta.getString("summary")); + } + operation + .setGroup(trim(annoMeta.getString("group"))) + .setVersion(trim(annoMeta.getString("version"))) + .setOperationId(trim(annoMeta.getString("id"))) + .setSummary(summary) + .setDescription(trim(annoMeta.getString("description"))) + .setDeprecated(annoMeta.getBoolean("deprecated")) + .setExtensions(Helper.toProperties(annoMeta.getStringArray("extensions"))); + + return chain.resolve(operation, methodMeta, ctx); + } + + @Override + public Schema resolve(ParameterMeta parameter, SchemaContext context, SchemaChain chain) { + AnnotationMeta annoMeta = parameter.getAnnotation(Annotations.Schema); + if (annoMeta == null) { + return chain.resolve(parameter, context); + } + if (annoMeta.getBoolean(HIDDEN)) { + return null; + } + + Class impl = annoMeta.getClass("implementation"); + Schema schema = impl == Void.class ? chain.resolve(parameter, context) : context.resolve(impl); + + setValue(annoMeta, "group", schema::setGroup); + setValue(annoMeta, "version", schema::setVersion); + setValue(annoMeta, "type", v -> schema.setType(Type.valueOf(v))); + setValue(annoMeta, "format", schema::setFormat); + setValue(annoMeta, "name", schema::setName); + String title = trim(annoMeta.getValue()); + schema.setTitle(title == null ? trim(annoMeta.getString("title")) : title); + setValue(annoMeta, "description", schema::setDescription); + setValue(annoMeta, "defaultValue", schema::setDefaultValue); + setValue(annoMeta, "max", v -> schema.setMaxLength(Integer.parseInt(v))); + setValue(annoMeta, "min", v -> schema.setMinLength(Integer.parseInt(v))); + setValue(annoMeta, "pattern", schema::setPattern); + setValue(annoMeta, "example", schema::setExample); + String[] enumItems = trim(annoMeta.getStringArray("enumeration")); + if (enumItems != null) { + schema.setEnumeration(Arrays.asList(enumItems)); + } + setBoolValue(annoMeta, "required", schema::setRequired); + setBoolValue(annoMeta, "readOnly", schema::setReadOnly); + setBoolValue(annoMeta, "writeOnly", schema::setWriteOnly); + setBoolValue(annoMeta, "nullable", schema::setNullable); + setBoolValue(annoMeta, "deprecated", schema::setDeprecated); + schema.setExtensions(Helper.toProperties(annoMeta.getStringArray("extensions"))); + + return chain.resolve(parameter, context); + } + + @Override + public Boolean acceptProperty(BeanMeta bean, PropertyMeta property) { + AnnotationMeta annoMeta = property.getAnnotation(Annotations.Schema); + return annoMeta == null ? null : annoMeta.getBoolean(HIDDEN); + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/JavadocOpenAPIDefinitionResolver.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/JavadocOpenAPIDefinitionResolver.java new file mode 100644 index 00000000000..e1c5b81712f --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/JavadocOpenAPIDefinitionResolver.java @@ -0,0 +1,344 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.rpc.protocol.tri.rest.support.swagger; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.common.utils.LRUCache; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta.ReturnParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIDefinitionResolver; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Info; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; + +import java.lang.ref.WeakReference; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import com.github.therapi.runtimejavadoc.ClassJavadoc; +import com.github.therapi.runtimejavadoc.Comment; +import com.github.therapi.runtimejavadoc.CommentFormatter; +import com.github.therapi.runtimejavadoc.FieldJavadoc; +import com.github.therapi.runtimejavadoc.MethodJavadoc; +import com.github.therapi.runtimejavadoc.ParamJavadoc; +import com.github.therapi.runtimejavadoc.RuntimeJavadoc; +import com.github.therapi.runtimejavadoc.internal.MethodSignature; +import com.github.therapi.runtimejavadoc.internal.RuntimeJavadocHelper; + +@Activate(order = -10000, onClass = "com.github.therapi.runtimejavadoc.RuntimeJavadoc") +public class JavadocOpenAPIDefinitionResolver implements OpenAPIDefinitionResolver, OpenAPISchemaResolver { + + private final LRUCache, WeakReference> cache = new LRUCache<>(128); + private final CommentFormatter formatter = new CommentFormatter(); + + @Override + public OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta, OpenAPIChain chain) { + openAPI = chain.resolve(openAPI, serviceMeta); + if (openAPI == null) { + return null; + } + + Info info = openAPI.getInfo(); + if (info == null) { + openAPI.setInfo(info = new Info()); + } + + if (info.getSummary() != null || info.getDescription() != null) { + return openAPI; + } + + ClassJavadoc javadoc = getClassJavadoc(serviceMeta.getType()).javadoc; + if (javadoc.isEmpty()) { + return openAPI; + } + + populateComment(javadoc.getComment(), info::setSummary, info::setDescription); + return openAPI; + } + + @Override + public Collection resolve(PathItem pathItem, MethodMeta methodMeta, OperationContext context) { + return null; + } + + @Override + public Operation resolve(Operation operation, MethodMeta methodMeta, OperationContext ctx, OperationChain chain) { + operation = chain.resolve(operation, methodMeta, ctx); + if (operation == null) { + return null; + } + + Method method = methodMeta.getMethod(); + ClassJavadocWrapper javadoc = getClassJavadoc(method.getDeclaringClass()); + if (javadoc.isEmpty()) { + return operation; + } + + if (operation.getSummary() == null && operation.getDescription() == null) { + MethodJavadoc methodJavadoc = javadoc.getMethod(method); + if (methodJavadoc != null) { + populateComment(methodJavadoc.getComment(), operation::setSummary, operation::setDescription); + } + } + + List parameters = operation.getParameters(); + if (parameters != null) { + for (Parameter parameter : parameters) { + if (parameter.getDescription() != null) { + continue; + } + + ParameterMeta meta = parameter.getMeta(); + if (!(meta instanceof MethodParameterMeta)) { + continue; + } + + populateComment(javadoc.getParameter(method, parameter.getName()), null, parameter::setDescription); + } + } + + return operation; + } + + @Override + public Schema resolve(ParameterMeta parameter, SchemaContext context, SchemaChain chain) { + Schema schema = chain.resolve(parameter, context); + if (schema == null) { + return null; + } + + if (schema.getTitle() != null || schema.getDescription() != null) { + return schema; + } + + Comment comment = null; + if (parameter instanceof MethodParameterMeta) { + MethodParameterMeta meta = (MethodParameterMeta) parameter; + Method method = meta.getMethod(); + comment = getClassJavadoc(method.getDeclaringClass()).getParameter(method, parameter.getName()); + } else if (parameter instanceof ReturnParameterMeta) { + ReturnParameterMeta meta = (ReturnParameterMeta) parameter; + Method method = meta.getMethod(); + MethodJavadoc methodJavadoc = + getClassJavadoc(method.getDeclaringClass()).getMethod(method); + if (methodJavadoc != null) { + comment = methodJavadoc.getReturns(); + } + } else { + for (AnnotatedElement element : parameter.getAnnotatedElements()) { + if (element instanceof Class) { + comment = getClassJavadoc((Class) element).getClassComment(); + } else if (element instanceof Field) { + Field field = (Field) element; + + ClassJavadocWrapper javadoc = getClassJavadoc(field.getDeclaringClass()); + FieldJavadoc fieldJavadoc = javadoc.getField(field); + if (fieldJavadoc != null) { + comment = fieldJavadoc.getComment(); + break; + } + + ParamJavadoc paramJavadoc = javadoc.getRecordComponent(field.getName()); + if (paramJavadoc != null) { + comment = paramJavadoc.getComment(); + break; + } + } else if (element instanceof Method) { + Method method = (Method) element; + + ClassJavadocWrapper javadoc = getClassJavadoc(method.getDeclaringClass()); + MethodJavadoc methodJavadoc = javadoc.getMethod(method); + + if (methodJavadoc != null) { + comment = methodJavadoc.getReturns(); + break; + } + } + } + } + + populateComment(comment, schema::setTitle, schema::setDescription); + return schema; + } + + private ClassJavadocWrapper getClassJavadoc(Class clazz) { + WeakReference ref = cache.get(clazz); + ClassJavadocWrapper javadoc = ref == null ? null : ref.get(); + if (javadoc == null) { + javadoc = new ClassJavadocWrapper(RuntimeJavadoc.getJavadoc(clazz)); + cache.put(clazz, new WeakReference<>(javadoc)); + } + return javadoc; + } + + private void populateComment(Comment comment, Consumer sConsumer, Consumer dConsumer) { + if (comment == null) { + return; + } + + String description = formatter.format(comment); + if (sConsumer == null) { + dConsumer.accept(description); + return; + } + + String summary = getFirstSentence(description); + sConsumer.accept(summary); + if (description.equals(summary)) { + return; + } + dConsumer.accept(description); + } + + private static String getFirstSentence(String text) { + if (StringUtils.isEmpty(text)) { + return text; + } + int pOpenIndex = text.indexOf("

"); + int pCloseIndex = text.indexOf("

"); + int dotIndex = text.indexOf("."); + if (pOpenIndex != -1) { + if (pOpenIndex == 0 && pCloseIndex != -1) { + if (dotIndex != -1) { + return text.substring(3, Math.min(pCloseIndex, dotIndex)); + } + return text.substring(3, pCloseIndex); + } + if (dotIndex != -1) { + return text.substring(0, Math.min(pOpenIndex, dotIndex)); + } + return text.substring(0, pOpenIndex); + } + if (dotIndex != -1 && text.length() != dotIndex + 1 && Character.isWhitespace(text.charAt(dotIndex + 1))) { + return text.substring(0, dotIndex + 1); + } + return text; + } + + private static final class ClassJavadocWrapper { + + private static final Map MAPPING = new LinkedHashMap<>(); + private static Field PARAMS; + + public final ClassJavadoc javadoc; + public Map fields; + public Map methods; + public Map recordComponents; + + static { + try { + Field[] fields = ClassJavadoc.class.getDeclaredFields(); + Field[] wFields = ClassJavadocWrapper.class.getFields(); + for (Field field : fields) { + field.setAccessible(true); + for (Field wField : wFields) { + if (wField.getName().equals(field.getName())) { + MAPPING.put(field, wField); + break; + } + } + } + PARAMS = MethodJavadoc.class.getDeclaredField("params"); + PARAMS.setAccessible(true); + } catch (Throwable ignored) { + } + } + + public ClassJavadocWrapper(ClassJavadoc javadoc) { + this.javadoc = javadoc; + try { + for (Map.Entry entry : MAPPING.entrySet()) { + entry.getValue().set(this, entry.getKey().get(javadoc)); + } + } catch (Throwable ignored) { + } + } + + public boolean isEmpty() { + return javadoc.isEmpty(); + } + + public Comment getClassComment() { + return javadoc.getComment(); + } + + public FieldJavadoc getField(Field field) { + if (fields == null) { + return null; + } + FieldJavadoc fieldJavadoc = fields.get(field.getName()); + return fieldJavadoc == null || fieldJavadoc.isEmpty() ? null : fieldJavadoc; + } + + public MethodJavadoc getMethod(Method method) { + if (methods == null) { + return null; + } + MethodJavadoc methodJavadoc = methods.get(MethodSignature.from(method)); + if (methodJavadoc != null && !methodJavadoc.isEmpty()) { + return methodJavadoc; + } + Method bridgeMethod = RuntimeJavadocHelper.findBridgeMethod(method); + if (bridgeMethod != null && bridgeMethod != method) { + methodJavadoc = methods.get(MethodSignature.from(bridgeMethod)); + if (methodJavadoc != null && !methodJavadoc.isEmpty()) { + return methodJavadoc; + } + } + return null; + } + + @SuppressWarnings("unchecked") + public Comment getParameter(Method method, String name) { + if (methods == null) { + return null; + } + MethodJavadoc methodJavadoc = methods.get(MethodSignature.from(method)); + if (methodJavadoc == null || PARAMS == null) { + return null; + } + try { + Map params = (Map) PARAMS.get(methodJavadoc); + ParamJavadoc paramJavadoc = params.get(name); + if (paramJavadoc != null) { + return paramJavadoc.getComment(); + } + } catch (Throwable ignored) { + } + return null; + } + + public ParamJavadoc getRecordComponent(String name) { + return recordComponents == null ? null : recordComponents.get(name); + } + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/RedocRequestHandler.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/RedocRequestHandler.java new file mode 100644 index 00000000000..3407a94bab4 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/RedocRequestHandler.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.dubbo.rpc.protocol.tri.rest.support.swagger; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.common.io.StreamUtils; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.nested.OpenAPIConfig; +import org.apache.dubbo.remoting.http12.HttpRequest; +import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.HttpResult; +import org.apache.dubbo.remoting.http12.HttpStatus; +import org.apache.dubbo.remoting.http12.exception.HttpStatusException; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.ConfigFactory; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Constants; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIRequestHandler; +import org.apache.dubbo.rpc.protocol.tri.rest.util.PathUtils; +import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import static java.nio.charset.StandardCharsets.UTF_8; + +@Activate +public class RedocRequestHandler implements OpenAPIRequestHandler { + + private static final String DEFAULT_CDN = "https://cdn.redoc.ly/redoc/latest/bundles"; + private static final String INDEX_PATH = "/META-INF/resources/redoc/index.html"; + + private final ConfigFactory configFactory; + + private OpenAPIConfig config; + + public RedocRequestHandler(FrameworkModel frameworkModel) { + configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class); + } + + private OpenAPIConfig getConfig() { + if (config == null) { + config = configFactory.getGlobalConfig(); + } + return config; + } + + @Override + public String[] getPaths() { + return new String[] {"/redoc/{*path}"}; + } + + @Override + public HttpResult handle(String path, HttpRequest request, HttpResponse response) { + String resPath = RequestUtils.getPathVariable(request, "path"); + if (StringUtils.isEmpty(resPath)) { + throw HttpResult.found(PathUtils.join(request.path(), "index.html")).toPayload(); + } + String requestPath = StringUtils.substringBeforeLast(resPath, '.'); + if (requestPath.equals("index")) { + return handleIndex(request.parameter("group", Constants.DEFAULT_GROUP)); + } else if (WebjarHelper.ENABLED && requestPath.startsWith("assets/")) { + return WebjarHelper.getInstance().handleAssets("redoc", resPath.substring(7)); + } + throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode()); + } + + private HttpResult handleIndex(String group) { + Map variables = new HashMap<>(4); + + OpenAPIConfig config = getConfig(); + String cdn = config.getSetting("redoc.cdn"); + if (cdn == null) { + if (WebjarHelper.ENABLED && WebjarHelper.getInstance().hasWebjar("redoc")) { + cdn = "./assets"; + } else { + cdn = DEFAULT_CDN; + } + } + variables.put("redoc.cdn", cdn); + variables.put("group", group); + try { + String content = StreamUtils.toString(getClass().getResourceAsStream(INDEX_PATH)); + return HttpResult.of(Helper.render(content, variables::get).getBytes(UTF_8)); + } catch (IOException e) { + throw new HttpStatusException(HttpStatus.INTERNAL_SERVER_ERROR.getCode(), e); + } + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java new file mode 100644 index 00000000000..0f3446d33ca --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java @@ -0,0 +1,258 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.rpc.protocol.tri.rest.support.swagger; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.PropertyMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Constants; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIDefinitionResolver; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaPredicate; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Contact; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ExternalDocs; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Info; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.License; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema.Type; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Tag; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +import io.swagger.v3.oas.annotations.ExternalDocumentation; +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.extensions.ExtensionProperty; +import io.swagger.v3.oas.annotations.media.Schema.AccessMode; +import io.swagger.v3.oas.annotations.media.Schema.RequiredMode; + +import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.setValue; +import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.trim; + +@Activate(order = 50, onClass = "io.swagger.v3.oas.annotations.OpenAPIDefinition") +public final class SwaggerOpenAPIDefinitionResolver + implements OpenAPIDefinitionResolver, OpenAPISchemaResolver, OpenAPISchemaPredicate { + + @Override + public OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta, OpenAPIChain chain) { + AnnotationMeta annoMeta = serviceMeta.findAnnotation(OpenAPIDefinition.class); + if (annoMeta == null) { + return chain.resolve(openAPI, serviceMeta); + } + if (serviceMeta.isHierarchyAnnotated(Hidden.class)) { + return null; + } + + OpenAPIDefinition anno = annoMeta.getAnnotation(); + + Info info = openAPI.getInfo(); + if (info == null) { + openAPI.setInfo(info = new Info()); + } + + io.swagger.v3.oas.annotations.info.Info infoAnn = anno.info(); + info.setTitle(trim(infoAnn.title())) + .setDescription(trim(infoAnn.description())) + .setVersion(trim(infoAnn.version())) + .setExtensions(toProperties(infoAnn.extensions())); + + Contact contact = new Contact(); + info.setContact(contact); + io.swagger.v3.oas.annotations.info.Contact contactAnn = infoAnn.contact(); + contact.setName(trim(contactAnn.name())) + .setEmail(trim(contactAnn.email())) + .setUrl(trim(contactAnn.url())) + .setExtensions(toProperties(contactAnn.extensions())); + + License license = new License(); + info.setLicense(license); + io.swagger.v3.oas.annotations.info.License licenseAnn = infoAnn.license(); + license.setName(trim(licenseAnn.name())) + .setUrl(trim(licenseAnn.url())) + .setExtensions(toProperties(licenseAnn.extensions())); + + for (io.swagger.v3.oas.annotations.tags.Tag tagAnn : anno.tags()) { + openAPI.addTag(new Tag() + .setName(trim(tagAnn.name())) + .setDescription(trim(tagAnn.description())) + .setExternalDocs(toExternalDocs(tagAnn.externalDocs())) + .setExtensions(toProperties(tagAnn.extensions()))); + } + + openAPI.setExternalDocs(toExternalDocs(anno.externalDocs())); + + Map properties = toProperties(anno.extensions()); + if (properties != null) { + String group = properties.remove(Constants.X_API_GROUP); + if (group != null) { + openAPI.setGroup(group); + } + openAPI.setExtensions(properties); + } + + return chain.resolve(openAPI, serviceMeta); + } + + private static Map toProperties(io.swagger.v3.oas.annotations.extensions.Extension[] extensions) { + int len = extensions.length; + if (len == 0) { + return null; + } + Map properties = CollectionUtils.newLinkedHashMap(extensions.length); + for (io.swagger.v3.oas.annotations.extensions.Extension extension : extensions) { + for (ExtensionProperty property : extension.properties()) { + properties.put(property.name(), property.value()); + } + } + return properties; + } + + private static ExternalDocs toExternalDocs(ExternalDocumentation anno) { + return new ExternalDocs() + .setDescription(trim(anno.description())) + .setUrl(trim(anno.url())) + .setExtensions(toProperties(anno.extensions())); + } + + @Override + public Collection resolve(PathItem pathItem, MethodMeta methodMeta, OperationContext context) { + AnnotationMeta annoMeta = + methodMeta.findAnnotation(io.swagger.v3.oas.annotations.Operation.class); + if (annoMeta == null) { + return null; + } + String method = trim(annoMeta.getAnnotation().method()); + if (method == null) { + return null; + } + return Collections.singletonList(HttpMethods.of(method.toUpperCase())); + } + + @Override + public Operation resolve(Operation operation, MethodMeta methodMeta, OperationContext ctx, OperationChain chain) { + AnnotationMeta annoMeta = + methodMeta.findAnnotation(io.swagger.v3.oas.annotations.Operation.class); + if (annoMeta == null) { + return chain.resolve(operation, methodMeta, ctx); + } + io.swagger.v3.oas.annotations.Operation anno = annoMeta.getAnnotation(); + if (anno.hidden() || methodMeta.isHierarchyAnnotated(Hidden.class)) { + return null; + } + + String method = trim(anno.method()); + if (method != null) { + operation.setHttpMethod(HttpMethods.of(method.toUpperCase())); + } + for (String tag : anno.tags()) { + operation.addTag(tag); + } + Map properties = toProperties(anno.extensions()); + if (properties != null) { + String group = properties.remove(Constants.X_API_GROUP); + if (group != null) { + operation.setGroup(group); + } + String version = properties.remove(Constants.X_API_VERSION); + if (version != null) { + operation.setVersion(version); + } + operation.setExtensions(properties); + } + operation + .setSummary(trim(anno.summary())) + .setDescription(trim(anno.description())) + .setExternalDocs(toExternalDocs(anno.externalDocs())) + .setOperationId(trim(anno.operationId())) + .setDeprecated(anno.deprecated() ? Boolean.TRUE : null); + + return chain.resolve(operation, methodMeta, ctx); + } + + @Override + public Schema resolve(ParameterMeta parameter, SchemaContext context, SchemaChain chain) { + AnnotationMeta annoMeta = + parameter.getAnnotation(io.swagger.v3.oas.annotations.media.Schema.class); + if (annoMeta == null) { + return chain.resolve(parameter, context); + } + io.swagger.v3.oas.annotations.media.Schema anno = annoMeta.getAnnotation(); + if (anno.hidden() || parameter.isHierarchyAnnotated(Hidden.class)) { + return null; + } + Schema schema = chain.resolve(parameter, context); + if (schema == null) { + return null; + } + + Map properties = toProperties(anno.extensions()); + if (properties != null) { + String group = properties.remove(Constants.X_API_GROUP); + if (group != null) { + schema.setGroup(group); + } + String version = properties.remove(Constants.X_API_VERSION); + if (version != null) { + schema.setVersion(version); + } + schema.setExtensions(properties); + } + + setValue(anno::type, v -> schema.setType(Type.valueOf(v))); + setValue(anno::format, schema::setFormat); + setValue(anno::name, schema::setName); + setValue(anno::title, schema::setTitle); + setValue(anno::description, schema::setDescription); + setValue(anno::defaultValue, schema::setDefaultValue); + setValue(anno::pattern, schema::setPattern); + setValue(anno::example, schema::setExample); + String[] enumItems = trim(anno.allowableValues()); + if (enumItems != null) { + schema.setEnumeration(Arrays.asList(enumItems)); + } + schema.setRequired(anno.requiredMode() == RequiredMode.REQUIRED ? Boolean.TRUE : null); + schema.setReadOnly(anno.accessMode() == AccessMode.READ_ONLY ? Boolean.TRUE : null); + schema.setWriteOnly(anno.accessMode() == AccessMode.WRITE_ONLY ? Boolean.TRUE : null); + schema.setNullable(anno.nullable() ? Boolean.TRUE : null); + schema.setDeprecated(anno.deprecated() ? Boolean.TRUE : null); + + return chain.resolve(parameter, context); + } + + @Override + public Boolean acceptProperty(BeanMeta bean, PropertyMeta property) { + AnnotationMeta meta = + bean.getAnnotation(io.swagger.v3.oas.annotations.media.Schema.class); + if (meta == null) { + return null; + } + io.swagger.v3.oas.annotations.media.Schema schema = meta.getAnnotation(); + return schema.hidden() || bean.isHierarchyAnnotated(Hidden.class) ? false : null; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java new file mode 100644 index 00000000000..f8b8e921ea3 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.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.dubbo.rpc.protocol.tri.rest.support.swagger; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.common.io.StreamUtils; +import org.apache.dubbo.common.utils.JsonUtils; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.nested.OpenAPIConfig; +import org.apache.dubbo.remoting.http12.HttpRequest; +import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.HttpResult; +import org.apache.dubbo.remoting.http12.HttpStatus; +import org.apache.dubbo.remoting.http12.exception.HttpStatusException; +import org.apache.dubbo.remoting.http12.rest.OpenAPIService; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.ConfigFactory; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIRequestHandler; +import org.apache.dubbo.rpc.protocol.tri.rest.util.PathUtils; +import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import static java.nio.charset.StandardCharsets.UTF_8; + +@Activate +public class SwaggerUIRequestHandler implements OpenAPIRequestHandler { + + private static final String DEFAULT_CDN = "https://unpkg.com/swagger-ui-dist@5.18.2"; + private static final String INDEX_PATH = "/META-INF/resources/swagger-ui/index.html"; + + private final FrameworkModel frameworkModel; + private final ConfigFactory configFactory; + + private OpenAPIConfig config; + + public SwaggerUIRequestHandler(FrameworkModel frameworkModel) { + this.frameworkModel = frameworkModel; + configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class); + } + + private OpenAPIConfig getConfig() { + if (config == null) { + config = configFactory.getGlobalConfig(); + } + return config; + } + + @Override + public String[] getPaths() { + return new String[] {"/swagger-ui/{*path}"}; + } + + @Override + public HttpResult handle(String path, HttpRequest request, HttpResponse response) { + String resPath = RequestUtils.getPathVariable(request, "path"); + if (StringUtils.isEmpty(resPath)) { + throw HttpResult.found(PathUtils.join(request.uri(), "index.html")).toPayload(); + } + String requestPath = StringUtils.substringBeforeLast(resPath, '.'); + switch (requestPath) { + case "index": + return handleIndex(); + case "swagger-config": + return handleSwaggerConfig(); + default: + if (WebjarHelper.ENABLED && requestPath.startsWith("assets/")) { + return WebjarHelper.getInstance().handleAssets("swagger-ui", resPath.substring(7)); + } + } + throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode()); + } + + private HttpResult handleIndex() { + Map variables = new HashMap<>(4); + + OpenAPIConfig config = getConfig(); + String cdn = config.getSetting("swagger-ui.cdn"); + if (cdn == null) { + if (WebjarHelper.ENABLED && WebjarHelper.getInstance().hasWebjar("swagger-ui")) { + cdn = "./assets"; + } else { + cdn = DEFAULT_CDN; + } + } + variables.put("swagger-ui.cdn", cdn); + + Map settings = config.getSettings(); + if (settings != null) { + StringBuilder sb = new StringBuilder(); + for (Map.Entry entry : settings.entrySet()) { + String key = entry.getKey(); + if (key.startsWith("swagger-ui.settings.")) { + sb.append(",\n \"") + .append(key.substring(20)) + .append("\": ") + .append(entry.getValue()); + } + } + if (sb.length() > 0) { + variables.put("swagger-ui.settings", sb.toString()); + } + } + + try { + String content = StreamUtils.toString(getClass().getResourceAsStream(INDEX_PATH)); + return HttpResult.of(Helper.render(content, variables::get).getBytes(UTF_8)); + } catch (IOException e) { + throw new HttpStatusException(HttpStatus.INTERNAL_SERVER_ERROR.getCode(), e); + } + } + + private HttpResult handleSwaggerConfig() { + OpenAPIService openAPIService = frameworkModel.getBean(OpenAPIService.class); + if (openAPIService == null) { + return HttpResult.notFound(); + } + Collection groups = openAPIService.getOpenAPIGroups(); + List> urls = new ArrayList<>(); + for (String group : groups) { + Map url = new LinkedHashMap<>(4); + url.put("name", group); + url.put("url", "../api-docs/" + group); + urls.add(url); + } + + Map configMap = new LinkedHashMap<>(); + configMap.put("urls", urls); + return HttpResult.of(JsonUtils.toJson(configMap).getBytes(UTF_8)); + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/WebjarHelper.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/WebjarHelper.java new file mode 100644 index 00000000000..8e37f50bd42 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/WebjarHelper.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.dubbo.rpc.protocol.tri.rest.support.swagger; + +import org.apache.dubbo.common.io.StreamUtils; +import org.apache.dubbo.common.utils.ClassUtils; +import org.apache.dubbo.remoting.http12.HttpResult; +import org.apache.dubbo.remoting.http12.HttpStatus; +import org.apache.dubbo.remoting.http12.exception.HttpStatusException; + +import java.io.IOException; +import java.io.InputStream; + +import org.webjars.WebJarVersionLocator; + +public class WebjarHelper { + + public static final boolean ENABLED = ClassUtils.isPresent("org.webjars.WebJarVersionLocator"); + private static volatile WebjarHelper INSTANCE; + private final WebJarVersionLocator locator = new WebJarVersionLocator(); + + public static WebjarHelper getInstance() { + if (INSTANCE == null) { + synchronized (WebjarHelper.class) { + if (INSTANCE == null) { + INSTANCE = new WebjarHelper(); + } + } + } + return INSTANCE; + } + + public HttpResult handleAssets(String webjar, String path) { + try { + byte[] bytes = getWebjarResource(webjar, path); + if (bytes != null) { + return HttpResult.builder() + .header("Cache-Control", "public, max-age=604800") + .body(bytes) + .build(); + } + } catch (IOException ignored) { + } + throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode()); + } + + public boolean hasWebjar(String webjar) { + return locator.version(webjar) != null; + } + + private byte[] getWebjarResource(String webjar, String exactPath) throws IOException { + String fullPath = locator.fullPath(webjar, exactPath); + if (fullPath != null) { + InputStream is = WebJarVersionLocator.class.getClassLoader().getResourceAsStream(fullPath); + if (is != null) { + return StreamUtils.readBytes(is); + } + } + return null; + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer b/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer new file mode 100644 index 00000000000..ba3f5a02c45 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer @@ -0,0 +1 @@ +openapi=org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIScopeModelInitializer diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension b/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension new file mode 100644 index 00000000000..74eb520bcad --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension @@ -0,0 +1,6 @@ +resolver-basic=org.apache.dubbo.rpc.protocol.tri.rest.support.basic.BasicOpenAPIDefinitionResolver +resolver-swagger=org.apache.dubbo.rpc.protocol.tri.rest.support.swagger.SwaggerOpenAPIDefinitionResolver +resolver-javadoc=org.apache.dubbo.rpc.protocol.tri.rest.support.swagger.JavadocOpenAPIDefinitionResolver +naming-strategy-default=org.apache.dubbo.rpc.protocol.tri.rest.openapi.DefaultOpenAPINamingStrategy +handler-swagger-ui=org.apache.dubbo.rpc.protocol.tri.rest.support.swagger.SwaggerUIRequestHandler +handler-redoc=org.apache.dubbo.rpc.protocol.tri.rest.support.swagger.RedocRequestHandler diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/resources/redoc/index.html b/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/resources/redoc/index.html new file mode 100644 index 00000000000..68fd09cef73 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/resources/redoc/index.html @@ -0,0 +1,20 @@ + + + + + Redoc + + + + + + + + + + diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/resources/swagger-ui/index.html b/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/resources/swagger-ui/index.html new file mode 100644 index 00000000000..bf226824c91 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/resources/swagger-ui/index.html @@ -0,0 +1,52 @@ + + + + + + Swagger UI + + + + + + + +
+ + + + + + diff --git a/dubbo-plugin/dubbo-rest-spring/pom.xml b/dubbo-plugin/dubbo-rest-spring/pom.xml index 671cc8bd285..16619482aa1 100644 --- a/dubbo-plugin/dubbo-rest-spring/pom.xml +++ b/dubbo-plugin/dubbo-rest-spring/pom.xml @@ -19,9 +19,9 @@ 4.0.0 org.apache.dubbo - dubbo-plugin + dubbo-parent ${revision} - ../pom.xml + ../../pom.xml dubbo-rest-spring @@ -83,11 +83,27 @@ test-jar test + + com.google.protobuf + protobuf-java-util + test + org.spockframework spock-core test + + org.apache.dubbo + dubbo-test-check + ${project.parent.version} + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + @@ -111,9 +127,9 @@ rpc-rest-test - org.apache.dubbo + org.apache.dubbo.extensions dubbo-rpc-rest - 3.3.1-SNAPSHOT + 3.3.0 test diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/AbstractSpringArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/AbstractSpringArgumentResolver.java index 5f3b89e2789..70421f7e2c2 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/AbstractSpringArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/AbstractSpringArgumentResolver.java @@ -28,9 +28,11 @@ public abstract class AbstractSpringArgumentResolver extends AbstractAnnotationBaseArgumentResolver { @Override - protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann) { - boolean required = param.getType() != Optional.class && Helper.isRequired(ann); - return new NamedValueMeta(ann.getValue(), required, Helper.defaultValue(ann)); + protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta anno) { + return new NamedValueMeta( + anno.getValue(), + param.getType() != Optional.class && Helper.isRequired(anno), + Helper.defaultValue(anno)); } @Override diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BeanArgumentBinder.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BeanArgumentBinder.java index d020e5425ab..6f721ddfe4b 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BeanArgumentBinder.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BeanArgumentBinder.java @@ -16,12 +16,10 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.support.spring; -import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; -import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestException; import org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver; @@ -49,9 +47,8 @@ final class BeanArgumentBinder { private final ArgumentResolver argumentResolver; private final ConversionService conversionService; - BeanArgumentBinder(FrameworkModel frameworkModel, ConversionService conversionService) { - ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory(); - argumentResolver = beanFactory.getOrRegisterBean(CompositeArgumentResolver.class); + BeanArgumentBinder(CompositeArgumentResolver argumentResolver, ConversionService conversionService) { + this.argumentResolver = argumentResolver; this.conversionService = conversionService; } @@ -77,7 +74,14 @@ private Object createBean(ParameterMeta paramMeta, HttpRequest request, HttpResp if (Modifier.isAbstract(type.getModifiers())) { throw new IllegalStateException(Messages.ARGUMENT_COULD_NOT_RESOLVED.format(paramMeta.getDescription())); } - ConstructorMeta ct = CACHE.computeIfAbsent(type, k -> resolveConstructor(paramMeta.getToolKit(), null, type)); + ConstructorMeta ct = CACHE.computeIfAbsent(type, k -> { + try { + return resolveConstructor(paramMeta.getToolKit(), null, type); + } catch (IllegalArgumentException e) { + throw new IllegalStateException(Messages.ARGUMENT_COULD_NOT_RESOLVED.format(paramMeta.getDescription()) + + ", " + e.getMessage()); + } + }); ParameterMeta[] parameters = ct.getParameters(); int len = parameters.length; if (len == 0) { diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BindParamArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BindParamArgumentResolver.java index a4906b7aec4..e783023245c 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BindParamArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BindParamArgumentResolver.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.argument.AbstractAnnotationBaseArgumentResolver; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; @@ -36,8 +37,13 @@ public Class accept() { } @Override - protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann) { - return new NamedValueMeta(ann.getValue(), param.isAnnotated(Annotations.Nonnull), null); + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Param; + } + + @Override + protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta anno) { + return new NamedValueMeta(anno.getValue(), param.isAnnotated(Annotations.Nonnull)); } @Override diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/CookieValueArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/CookieValueArgumentResolver.java index 0e3767efff4..83bb983ac07 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/CookieValueArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/CookieValueArgumentResolver.java @@ -21,6 +21,7 @@ import org.apache.dubbo.remoting.http12.HttpCookie; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import java.lang.annotation.Annotation; @@ -38,6 +39,11 @@ public Class accept() { return Annotations.CookieValue.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Cookie; + } + @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { return request.cookie(meta.name()); diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/FallbackArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/FallbackArgumentResolver.java index 79e1121650b..e9e2806bea2 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/FallbackArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/FallbackArgumentResolver.java @@ -36,12 +36,12 @@ public boolean accept(ParameterMeta param) { @Override protected NamedValueMeta createNamedValueMeta(ParameterMeta param) { - return new NamedValueMeta(param.isAnnotated(Annotations.Nonnull), null); + return new NamedValueMeta(null, param.isAnnotated(Annotations.Nonnull)); } @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { - ParameterMeta parameter = meta.parameterMeta(); + ParameterMeta parameter = meta.parameter(); if (parameter.isSimple()) { return request.parameter(meta.name()); } diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/Helper.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/Helper.java index fd818c06770..26d38cbd61e 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/Helper.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/Helper.java @@ -19,13 +19,30 @@ import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import org.springframework.core.SpringVersion; +import org.springframework.http.ResponseEntity; +import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.ValueConstants; final class Helper { + public static boolean IS_SPRING_6; + + private static Method getStatusCode; + private static Method value; + private Helper() {} + static { + try { + String version = SpringVersion.getVersion(); + IS_SPRING_6 = StringUtils.hasLength(version) && version.charAt(0) >= '6'; + } catch (Throwable ignored) { + } + } + public static boolean isRequired(AnnotationMeta annotation) { return annotation.getBoolean("required"); } @@ -41,4 +58,19 @@ public static String defaultValue(AnnotationMeta annotation, String public static String defaultValue(String value) { return ValueConstants.DEFAULT_NONE.equals(value) ? null : value; } + + public static int getStatusCode(ResponseEntity entity) { + if (IS_SPRING_6) { + try { + if (getStatusCode == null) { + getStatusCode = ResponseEntity.class.getMethod("getStatusCode"); + value = getStatusCode.getReturnType().getMethod("value"); + } + return (Integer) value.invoke(getStatusCode.invoke(entity)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + return entity.getStatusCode().value(); + } } diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/MatrixVariableArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/MatrixVariableArgumentResolver.java index f68ff9cacf1..b894cfde354 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/MatrixVariableArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/MatrixVariableArgumentResolver.java @@ -20,6 +20,7 @@ import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; @@ -42,9 +43,17 @@ public Class accept() { } @Override - protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann) { + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.MatrixVariable; + } + + @Override + protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta anno) { return new MatrixNamedValueMeta( - ann.getValue(), Helper.isRequired(ann), Helper.defaultValue(ann), Helper.defaultValue(ann, "pathVar")); + anno.getValue(), + Helper.isRequired(anno), + Helper.defaultValue(anno), + Helper.defaultValue(anno, "pathVar")); } @Override diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/ModelAttributeArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/ModelAttributeArgumentResolver.java index 89b2581dd3e..56ce0f798f0 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/ModelAttributeArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/ModelAttributeArgumentResolver.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; import org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils; @@ -33,20 +34,25 @@ public Class accept() { return Annotations.ModelAttribute.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Param; + } + @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { - if (meta.parameterMeta().isSimple()) { + if (meta.parameter().isSimple()) { return request.parameter(meta.name()); } - return meta.parameterMeta().bind(request, response); + return meta.parameter().bind(request, response); } @Override protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { - if (meta.parameterMeta().isSimple()) { + if (meta.parameter().isSimple()) { return request.parameterValues(meta.name()); } - return meta.parameterMeta().bind(request, response); + return meta.parameter().bind(request, response); } @Override @@ -54,6 +60,6 @@ protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpR if (TypeUtils.isSimpleProperty(meta.nestedType(1))) { return RequestUtils.getParametersMap(request); } - return meta.parameterMeta().bind(request, response); + return meta.parameter().bind(request, response); } } diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/PathVariableArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/PathVariableArgumentResolver.java index a1c389f54f4..32cc2bbfc6f 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/PathVariableArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/PathVariableArgumentResolver.java @@ -20,11 +20,13 @@ import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; import org.apache.dubbo.rpc.protocol.tri.rest.RestParameterException; import org.apache.dubbo.rpc.protocol.tri.rest.argument.AnnotationBaseArgumentResolver; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; @@ -39,6 +41,11 @@ public Class accept() { return Annotations.PathVariable.type(); } + @Override + public NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta annotation) { + return new NamedValueMeta(annotation.getValue(), true).setParamType(ParamType.PathVariable); + } + @Override public Object resolve( ParameterMeta parameter, diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestAttributeArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestAttributeArgumentResolver.java index 7e61abcf442..d0523aa865f 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestAttributeArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestAttributeArgumentResolver.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import java.lang.annotation.Annotation; @@ -31,6 +32,11 @@ public Class accept() { return Annotations.RequestAttribute.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Attribute; + } + @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { return request.attribute(meta.name()); diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestBodyArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestBodyArgumentResolver.java index dcf3173f358..9ae5a7a2158 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestBodyArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestBodyArgumentResolver.java @@ -20,6 +20,7 @@ import org.apache.dubbo.common.io.StreamUtils; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.RestException; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; @@ -38,17 +39,22 @@ public Class accept() { } @Override - protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann) { - return new NamedValueMeta(Helper.isRequired(ann), null); + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Body; + } + + @Override + protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta anno) { + return new NamedValueMeta(null, Helper.isRequired(anno)); } @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { if (RequestUtils.isFormOrMultiPart(request)) { - if (meta.parameterMeta().isSimple()) { + if (meta.parameter().isSimple()) { return request.formParameter(meta.name()); } - return meta.parameterMeta().bind(request, response); + return meta.parameter().bind(request, response); } return RequestUtils.decodeBody(request, meta.genericType()); } diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestHeaderArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestHeaderArgumentResolver.java index df554d8eff2..c93ae084c9a 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestHeaderArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestHeaderArgumentResolver.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import java.lang.annotation.Annotation; @@ -31,6 +32,11 @@ public Class accept() { return Annotations.RequestHeader.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Header; + } + @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { return request.header(meta.name()); @@ -43,6 +49,6 @@ protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request @Override protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { - return request.headers(); + return request.headers().asMap(); } } diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestParamArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestParamArgumentResolver.java index 56a1b1577f4..21889890e8b 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestParamArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestParamArgumentResolver.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; @@ -32,6 +33,11 @@ public Class accept() { return Annotations.RequestParam.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Param; + } + @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { return request.parameter(meta.name()); diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestPartArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestPartArgumentResolver.java index 7d17d3bb472..834807d0f74 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestPartArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestPartArgumentResolver.java @@ -20,6 +20,7 @@ import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpRequest.FileUpload; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; @@ -39,8 +40,13 @@ public Class accept() { } @Override - protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann) { - return new NamedValueMeta(ann.getValue(), Helper.isRequired(ann), null); + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Part; + } + + @Override + protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta anno) { + return new NamedValueMeta(anno.getValue(), Helper.isRequired(anno)); } @Override diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringMvcRequestMappingResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringMvcRequestMappingResolver.java index 428f4f9d18f..b80de0d00a2 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringMvcRequestMappingResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringMvcRequestMappingResolver.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.constants.CommonConstants; import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.nested.RestConfig; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.cors.CorsUtils; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMapping; @@ -35,15 +36,19 @@ @Activate(onClass = "org.springframework.web.bind.annotation.RequestMapping") public class SpringMvcRequestMappingResolver implements RequestMappingResolver { - private final FrameworkModel frameworkModel; private final RestToolKit toolKit; + private RestConfig restConfig; private CorsMeta globalCorsMeta; public SpringMvcRequestMappingResolver(FrameworkModel frameworkModel) { - this.frameworkModel = frameworkModel; toolKit = new SpringRestToolKit(frameworkModel); } + @Override + public void setRestConfig(RestConfig restConfig) { + this.restConfig = restConfig; + } + @Override public RestToolKit getRestToolKit() { return toolKit; @@ -125,7 +130,7 @@ private Builder builder( private CorsMeta buildCorsMeta(AnnotationMeta crossOrigin, String[] methods) { if (globalCorsMeta == null) { - globalCorsMeta = CorsUtils.getGlobalCorsMeta(frameworkModel); + globalCorsMeta = CorsUtils.getGlobalCorsMeta(restConfig); } if (crossOrigin == null) { return globalCorsMeta; diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringResponseRestFilter.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringResponseRestFilter.java index 05458703c58..a354093f3f1 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringResponseRestFilter.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringResponseRestFilter.java @@ -57,7 +57,7 @@ public class SpringResponseRestFilter implements RestFilter, Listener { private final Map> cache = CollectionUtils.newConcurrentHashMap(); public SpringResponseRestFilter(FrameworkModel frameworkModel) { - argumentResolver = frameworkModel.getBeanFactory().getOrRegisterBean(CompositeArgumentResolver.class); + argumentResolver = frameworkModel.getOrRegisterBean(CompositeArgumentResolver.class); } @Override @@ -87,7 +87,7 @@ public void onResponse(Result result, HttpRequest request, HttpResponse response ResponseEntity entity = (ResponseEntity) value; result.setValue(HttpResult.builder() .body(entity.getBody()) - .status(entity.getStatusCode().value()) + .status(Helper.getStatusCode(entity)) .headers(entity.getHeaders()) .build()); return; @@ -181,7 +181,7 @@ private static final class Key { } @Override - @SuppressWarnings("EqualsWhichDoesntCheckParameterClass") + @SuppressWarnings({"EqualsWhichDoesntCheckParameterClass", "EqualsDoesntCheckParameterClass"}) public boolean equals(Object obj) { Key other = (Key) obj; return method.equals(other.method) && type.equals(other.type); diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringRestToolKit.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringRestToolKit.java index e8c75ae6c89..38b20df5459 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringRestToolKit.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringRestToolKit.java @@ -19,6 +19,8 @@ import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.common.utils.DefaultParameterNameReader; +import org.apache.dubbo.common.utils.ParameterNameReader; import org.apache.dubbo.config.spring.extension.SpringExtensionInjector; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; @@ -27,15 +29,18 @@ import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; import org.apache.dubbo.rpc.protocol.tri.rest.RestException; +import org.apache.dubbo.rpc.protocol.tri.rest.argument.CompositeArgumentResolver; import org.apache.dubbo.rpc.protocol.tri.rest.argument.GeneralTypeConverter; import org.apache.dubbo.rpc.protocol.tri.rest.argument.TypeConverter; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit; import org.apache.dubbo.rpc.protocol.tri.rest.util.RestUtils; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Collection; import java.util.Map; @@ -43,9 +48,7 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.MethodParameter; -import org.springframework.core.ParameterNameDiscoverer; import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.TypeDescriptor; @@ -63,7 +66,8 @@ final class SpringRestToolKit implements RestToolKit { private final ConversionService conversionService; private final TypeConverter typeConverter; private final BeanArgumentBinder argumentBinder; - private final ParameterNameDiscoverer discoverer; + private final ParameterNameReader parameterNameReader; + private final CompositeArgumentResolver argumentResolver; public SpringRestToolKit(FrameworkModel frameworkModel) { ApplicationModel applicationModel = frameworkModel.defaultApplication(); @@ -79,13 +83,14 @@ public SpringRestToolKit(FrameworkModel frameworkModel) { configuration = new ConfigurationWrapper(applicationModel); } if (context != null && context.containsBean("mvcConversionService")) { - conversionService = context.getBean(ConversionService.class, "mvcConversionService"); + conversionService = context.getBean("mvcConversionService", ConversionService.class); } else { conversionService = DefaultConversionService.getSharedInstance(); } - typeConverter = frameworkModel.getBeanFactory().getOrRegisterBean(GeneralTypeConverter.class); - discoverer = new DefaultParameterNameDiscoverer(); - argumentBinder = new BeanArgumentBinder(frameworkModel, conversionService); + typeConverter = frameworkModel.getOrRegisterBean(GeneralTypeConverter.class); + parameterNameReader = frameworkModel.getOrRegisterBean(DefaultParameterNameReader.class); + argumentResolver = frameworkModel.getOrRegisterBean(CompositeArgumentResolver.class); + argumentBinder = new BeanArgumentBinder(argumentResolver, conversionService); } @Override @@ -149,9 +154,19 @@ public Object bind(ParameterMeta parameter, HttpRequest request, HttpResponse re return argumentBinder.bind(parameter, request, response); } + @Override + public NamedValueMeta getNamedValueMeta(ParameterMeta parameter) { + return argumentResolver.getNamedValueMeta(parameter); + } + @Override public String[] getParameterNames(Method method) { - return discoverer.getParameterNames(method); + return parameterNameReader.readParameterNames(method); + } + + @Override + public String[] getParameterNames(Constructor ctor) { + return parameterNameReader.readParameterNames(ctor); } @Override diff --git a/dubbo-plugin/dubbo-security/pom.xml b/dubbo-plugin/dubbo-security/pom.xml index bcc16b68ea1..401ff1ca465 100644 --- a/dubbo-plugin/dubbo-security/pom.xml +++ b/dubbo-plugin/dubbo-security/pom.xml @@ -19,9 +19,9 @@ 4.0.0 org.apache.dubbo - dubbo-plugin + dubbo-parent ${revision} - ../pom.xml + ../../pom.xml dubbo-security @@ -93,6 +93,17 @@ ${project.version} test + + org.apache.dubbo + dubbo-test-check + ${project.parent.version} + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + diff --git a/dubbo-plugin/dubbo-spring-security/pom.xml b/dubbo-plugin/dubbo-spring-security/pom.xml index 5bb4688fbea..32f4ac9e559 100644 --- a/dubbo-plugin/dubbo-spring-security/pom.xml +++ b/dubbo-plugin/dubbo-spring-security/pom.xml @@ -19,9 +19,9 @@ 4.0.0 org.apache.dubbo - dubbo-plugin + dubbo-parent ${revision} - ../pom.xml + ../../pom.xml dubbo-spring-security @@ -84,6 +84,18 @@ + + org.apache.dubbo + dubbo-test-check + ${project.parent.version} + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + + diff --git a/dubbo-plugin/dubbo-spring-security/src/main/java/org/apache/dubbo/spring/security/model/SecurityScopeModelInitializer.java b/dubbo-plugin/dubbo-spring-security/src/main/java/org/apache/dubbo/spring/security/model/SecurityScopeModelInitializer.java index 1a9531d5631..3fcd611038a 100644 --- a/dubbo-plugin/dubbo-spring-security/src/main/java/org/apache/dubbo/spring/security/model/SecurityScopeModelInitializer.java +++ b/dubbo-plugin/dubbo-spring-security/src/main/java/org/apache/dubbo/spring/security/model/SecurityScopeModelInitializer.java @@ -20,9 +20,7 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; import org.apache.dubbo.spring.security.jackson.ObjectMapperCodec; import org.apache.dubbo.spring.security.jackson.ObjectMapperCodecCustomer; @@ -69,10 +67,4 @@ public void initializeFrameworkModel(FrameworkModel frameworkModel) { t); } } - - @Override - public void initializeApplicationModel(ApplicationModel applicationModel) {} - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-plugin/dubbo-triple-servlet/pom.xml b/dubbo-plugin/dubbo-triple-servlet/pom.xml index f15f9a13321..509656e5754 100644 --- a/dubbo-plugin/dubbo-triple-servlet/pom.xml +++ b/dubbo-plugin/dubbo-triple-servlet/pom.xml @@ -19,9 +19,9 @@ 4.0.0 org.apache.dubbo - dubbo-plugin + dubbo-parent ${revision} - ../pom.xml + ../../pom.xml dubbo-triple-servlet @@ -54,6 +54,17 @@ ${project.version} test + + org.apache.dubbo + dubbo-test-check + ${project.parent.version} + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + diff --git a/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/HttpMetadataAdapter.java b/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/HttpMetadataAdapter.java index 4ebfbf770c3..829d046497a 100644 --- a/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/HttpMetadataAdapter.java +++ b/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/HttpMetadataAdapter.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.servlet; +import org.apache.dubbo.remoting.http12.HttpHeaderNames; import org.apache.dubbo.remoting.http12.HttpHeaders; import org.apache.dubbo.remoting.http12.h2.Http2Header; @@ -23,6 +24,8 @@ import java.util.Enumeration; +import io.netty.handler.codec.http2.Http2Headers.PseudoHeaderName; + public final class HttpMetadataAdapter implements Http2Header { private final HttpServletRequest request; @@ -50,6 +53,10 @@ public HttpHeaders headers() { headers.add(key, ven.nextElement()); } } + headers.add(PseudoHeaderName.METHOD.value(), method()); + headers.add(PseudoHeaderName.SCHEME.value(), request.getScheme()); + headers.add(PseudoHeaderName.AUTHORITY.value(), request.getHeader(HttpHeaderNames.HOST.getName())); + headers.add(PseudoHeaderName.PROTOCOL.value(), request.getProtocol()); this.headers = headers; } return headers; diff --git a/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java b/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java index 85175d3d24e..749063dcc79 100644 --- a/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java +++ b/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java @@ -59,6 +59,8 @@ import java.util.Arrays; import java.util.Set; +import static org.apache.dubbo.rpc.protocol.tri.TripleConstants.UPGRADE_HEADER_KEY; + public class TripleFilter implements Filter { private static final Logger LOGGER = LoggerFactory.getLogger(TripleFilter.class); @@ -70,7 +72,7 @@ public class TripleFilter implements Filter { public void init(FilterConfig config) { FrameworkModel frameworkModel = FrameworkModel.defaultModel(); pathResolver = frameworkModel.getDefaultExtension(PathResolver.class); - mappingRegistry = frameworkModel.getBeanFactory().getOrRegisterBean(DefaultRequestMappingRegistry.class); + mappingRegistry = frameworkModel.getOrRegisterBean(DefaultRequestMappingRegistry.class); } @Override @@ -86,7 +88,7 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo return; } } else { - if (mappingRegistry.exists(request.getRequestURI(), request.getMethod())) { + if (notUpgradeRequest(request) && mappingRegistry.exists(request.getRequestURI(), request.getMethod())) { handleHttp1(request, response); return; } @@ -125,8 +127,10 @@ private void handleHttp1(HttpServletRequest request, HttpServletResponse respons channel, ServletExchanger.getUrl(), FrameworkModel.defaultModel()); channel.setGrpc(false); context.setTimeout(resolveTimeout(request, false)); - listener.onMetadata(new HttpMetadataAdapter(request)); ServletInputStream is = request.getInputStream(); + response.getOutputStream().setWriteListener(new TripleWriteListener(channel)); + + listener.onMetadata(new HttpMetadataAdapter(request)); listener.onData(new Http1InputMessage( is.available() == 0 ? StreamUtils.EMPTY : new ByteArrayInputStream(StreamUtils.readBytes(is)))); } catch (Throwable t) { @@ -153,6 +157,10 @@ private boolean hasGrpcMapping(HttpServletRequest request) { return pathResolver.resolve(path.getPath(), group, version) != null; } + private boolean notUpgradeRequest(HttpServletRequest request) { + return request.getHeader(UPGRADE_HEADER_KEY) == null; + } + private Http2ServerTransportListenerFactory determineHttp2ServerTransportListenerFactory(String contentType) { Set http2ServerTransportListenerFactories = FrameworkModel.defaultModel() .getExtensionLoader(Http2ServerTransportListenerFactory.class) diff --git a/dubbo-plugin/dubbo-triple-websocket/pom.xml b/dubbo-plugin/dubbo-triple-websocket/pom.xml new file mode 100644 index 00000000000..447074ccc97 --- /dev/null +++ b/dubbo-plugin/dubbo-triple-websocket/pom.xml @@ -0,0 +1,145 @@ + + + + 4.0.0 + + org.apache.dubbo + dubbo-parent + ${revision} + ../../pom.xml + + + dubbo-triple-websocket + + + 4.0.1 + 1.1 + ${project.build.directory}/generated-sources/java/org/apache/dubbo/rpc/protocol/tri + + + + + org.apache.dubbo + dubbo-rpc-triple + ${project.version} + + + org.apache.dubbo + dubbo-remoting-websocket + ${project.parent.version} + + + javax.servlet + javax.servlet-api + ${servlet4_version} + provided + + + jakarta.servlet + jakarta.servlet-api + provided + + + javax.websocket + javax.websocket-api + ${websocket_version} + provided + + + jakarta.websocket + jakarta.websocket-api + provided + + + jakarta.websocket + jakarta.websocket-client-api + provided + + + org.apache.dubbo + dubbo-remoting-netty4 + ${project.version} + test + + + + + + jdk-version-ge-17 + + [17,) + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + copy-sources + + run + + generate-sources + + + + + + + + + + + + + + + + import org.apache.dubbo.rpc.protocol.tri.ServletExchanger; + + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-sources + + add-source + + generate-sources + + + ${project.build.directory}/generated-sources/java + + + + + + + + + + diff --git a/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleBinaryMessageHandler.java b/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleBinaryMessageHandler.java new file mode 100644 index 00000000000..a507f6f1e42 --- /dev/null +++ b/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleBinaryMessageHandler.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.dubbo.rpc.protocol.tri.websocket; + +import org.apache.dubbo.remoting.http12.h2.Http2InputMessage; +import org.apache.dubbo.remoting.http12.h2.Http2InputMessageFrame; +import org.apache.dubbo.remoting.websocket.FinalFragmentByteArrayInputStream; +import org.apache.dubbo.remoting.websocket.WebSocketTransportListener; + +import javax.websocket.MessageHandler; + +import java.nio.ByteBuffer; + +public class TripleBinaryMessageHandler implements MessageHandler.Partial { + + private final WebSocketTransportListener webSocketTransportListener; + + public TripleBinaryMessageHandler(WebSocketTransportListener webSocketTransportListener) { + this.webSocketTransportListener = webSocketTransportListener; + } + + @Override + public void onMessage(ByteBuffer messagePart, boolean last) { + Http2InputMessage http2InputMessage = + new Http2InputMessageFrame(new FinalFragmentByteArrayInputStream(messagePart.array(), last), false); + webSocketTransportListener.onData(http2InputMessage); + } +} diff --git a/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleEndpoint.java b/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleEndpoint.java new file mode 100644 index 00000000000..54eb85fb6be --- /dev/null +++ b/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleEndpoint.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.dubbo.rpc.protocol.tri.websocket; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.io.StreamUtils; +import org.apache.dubbo.config.context.ConfigManager; +import org.apache.dubbo.config.nested.TripleConfig; +import org.apache.dubbo.remoting.http12.HttpHeaderNames; +import org.apache.dubbo.remoting.http12.HttpHeaders; +import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.remoting.http12.HttpStatus; +import org.apache.dubbo.remoting.http12.h2.Http2Header; +import org.apache.dubbo.remoting.http12.h2.Http2InputMessage; +import org.apache.dubbo.remoting.http12.h2.Http2InputMessageFrame; +import org.apache.dubbo.remoting.http12.h2.Http2MetadataFrame; +import org.apache.dubbo.remoting.http12.message.DefaultHttpHeaders; +import org.apache.dubbo.remoting.websocket.WebSocketTransportListener; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.ServletExchanger; + +import javax.websocket.CloseReason; +import javax.websocket.CloseReason.CloseCodes; +import javax.websocket.Endpoint; +import javax.websocket.EndpointConfig; +import javax.websocket.Session; + +import static org.apache.dubbo.rpc.protocol.tri.websocket.WebSocketConstants.TRIPLE_WEBSOCKET_LISTENER; + +public class TripleEndpoint extends Endpoint { + + @Override + public void onOpen(Session session, EndpointConfig config) { + String path = session.getRequestURI().getPath(); + HttpHeaders httpHeaders = new DefaultHttpHeaders(); + httpHeaders.set(HttpHeaderNames.PATH.getName(), path); + httpHeaders.set(HttpHeaderNames.METHOD.getName(), HttpMethods.POST.name()); + Http2Header http2Header = new Http2MetadataFrame(httpHeaders); + + URL url = ServletExchanger.getUrl(); + TripleConfig tripleConfig = ConfigManager.getProtocolOrDefault(url).getTripleOrDefault(); + + WebSocketStreamChannel webSocketStreamChannel = new WebSocketStreamChannel(session, tripleConfig); + WebSocketTransportListener webSocketTransportListener = + DefaultWebSocketServerTransportListenerFactory.INSTANCE.newInstance( + webSocketStreamChannel, url, FrameworkModel.defaultModel()); + webSocketTransportListener.onMetadata(http2Header); + session.addMessageHandler(new TripleTextMessageHandler(webSocketTransportListener)); + session.addMessageHandler(new TripleBinaryMessageHandler(webSocketTransportListener)); + session.getUserProperties().put(TRIPLE_WEBSOCKET_LISTENER, webSocketTransportListener); + } + + @Override + public void onClose(Session session, CloseReason closeReason) { + super.onClose(session, closeReason); + WebSocketTransportListener webSocketTransportListener = + (WebSocketTransportListener) session.getUserProperties().get(TRIPLE_WEBSOCKET_LISTENER); + if (webSocketTransportListener == null) { + return; + } + if (closeReason.getCloseCode().getCode() == CloseCodes.NORMAL_CLOSURE.getCode()) { + Http2InputMessage http2InputMessage = new Http2InputMessageFrame(StreamUtils.EMPTY, true); + webSocketTransportListener.onData(http2InputMessage); + return; + } + webSocketTransportListener.cancelByRemote(closeReason.getCloseCode().getCode()); + } + + @Override + public void onError(Session session, Throwable thr) { + super.onError(session, thr); + WebSocketTransportListener webSocketTransportListener = + (WebSocketTransportListener) session.getUserProperties().get(TRIPLE_WEBSOCKET_LISTENER); + if (webSocketTransportListener == null) { + return; + } + webSocketTransportListener.cancelByRemote(HttpStatus.INTERNAL_SERVER_ERROR.getCode()); + } +} diff --git a/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleTextMessageHandler.java b/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleTextMessageHandler.java new file mode 100644 index 00000000000..2aa962d6d18 --- /dev/null +++ b/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleTextMessageHandler.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.dubbo.rpc.protocol.tri.websocket; + +import org.apache.dubbo.remoting.http12.h2.Http2InputMessage; +import org.apache.dubbo.remoting.http12.h2.Http2InputMessageFrame; +import org.apache.dubbo.remoting.websocket.FinalFragmentByteArrayInputStream; +import org.apache.dubbo.remoting.websocket.WebSocketTransportListener; + +import javax.websocket.MessageHandler; + +public class TripleTextMessageHandler implements MessageHandler.Partial { + + private final WebSocketTransportListener webSocketTransportListener; + + public TripleTextMessageHandler(WebSocketTransportListener webSocketTransportListener) { + this.webSocketTransportListener = webSocketTransportListener; + } + + @Override + public void onMessage(String messagePart, boolean last) { + Http2InputMessage http2InputMessage = + new Http2InputMessageFrame(new FinalFragmentByteArrayInputStream(messagePart.getBytes(), last), false); + webSocketTransportListener.onData(http2InputMessage); + } +} diff --git a/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleWebSocketFilter.java b/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleWebSocketFilter.java new file mode 100644 index 00000000000..90391a38141 --- /dev/null +++ b/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/TripleWebSocketFilter.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.dubbo.rpc.protocol.tri.websocket; + +import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.ConcurrentHashSet; +import org.apache.dubbo.remoting.http12.HttpMethods; + +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 javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import javax.servlet.http.HttpServletResponse; +import javax.websocket.server.ServerContainer; +import javax.websocket.server.ServerEndpointConfig; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_REQUEST; +import static org.apache.dubbo.rpc.protocol.tri.TripleConstants.UPGRADE_HEADER_KEY; +import static org.apache.dubbo.rpc.protocol.tri.websocket.WebSocketConstants.TRIPLE_WEBSOCKET_REMOTE_ADDRESS; +import static org.apache.dubbo.rpc.protocol.tri.websocket.WebSocketConstants.TRIPLE_WEBSOCKET_UPGRADE_HEADER_VALUE; + +public class TripleWebSocketFilter implements Filter { + + private static final ErrorTypeAwareLogger LOG = LoggerFactory.getErrorTypeAwareLogger(TripleWebSocketFilter.class); + + private transient ServerContainer sc; + + private final Set existed = new ConcurrentHashSet<>(); + + @Override + public void init(FilterConfig filterConfig) { + sc = (ServerContainer) filterConfig.getServletContext().getAttribute(ServerContainer.class.getName()); + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + if (!isWebSocketUpgradeRequest(request, response)) { + chain.doFilter(request, response); + return; + } + HttpServletRequest hRequest = (HttpServletRequest) request; + HttpServletResponse hResponse = (HttpServletResponse) response; + String path; + String pathInfo = hRequest.getPathInfo(); + if (pathInfo == null) { + path = hRequest.getServletPath(); + } else { + path = hRequest.getServletPath() + pathInfo; + } + Map copiedMap = new HashMap<>(hRequest.getParameterMap()); + copiedMap.put( + TRIPLE_WEBSOCKET_REMOTE_ADDRESS, + new String[] {hRequest.getRemoteHost(), String.valueOf(hRequest.getRemotePort())}); + HttpServletRequestWrapper wrappedRequest = new HttpServletRequestWrapper(hRequest) { + @Override + public Map getParameterMap() { + return copiedMap; + } + }; + if (existed.contains(path)) { + chain.doFilter(wrappedRequest, hResponse); + return; + } + ServerEndpointConfig serverEndpointConfig = + ServerEndpointConfig.Builder.create(TripleEndpoint.class, path).build(); + try { + sc.addEndpoint(serverEndpointConfig); + existed.add(path); + } catch (Exception e) { + LOG.error(PROTOCOL_FAILED_REQUEST, "", "", "Failed to add endpoint", e); + hResponse.sendError(HttpServletResponse.SC_BAD_REQUEST); + return; + } + chain.doFilter(wrappedRequest, hResponse); + } + + @Override + public void destroy() {} + + public boolean isWebSocketUpgradeRequest(ServletRequest request, ServletResponse response) { + return ((request instanceof HttpServletRequest) + && (response instanceof HttpServletResponse) + && headerContainsToken( + (HttpServletRequest) request, UPGRADE_HEADER_KEY, TRIPLE_WEBSOCKET_UPGRADE_HEADER_VALUE) + && HttpMethods.GET.name().equals(((HttpServletRequest) request).getMethod())); + } + + private boolean headerContainsToken(HttpServletRequest req, String headerName, String target) { + Enumeration headers = req.getHeaders(headerName); + while (headers.hasMoreElements()) { + String header = headers.nextElement(); + String[] tokens = header.split(","); + for (String token : tokens) { + if (target.equalsIgnoreCase(token.trim())) { + return true; + } + } + } + return false; + } +} diff --git a/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/WebSocketConstants.java b/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/WebSocketConstants.java new file mode 100644 index 00000000000..467e5ae318b --- /dev/null +++ b/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/WebSocketConstants.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.dubbo.rpc.protocol.tri.websocket; + +public interface WebSocketConstants { + + String TRIPLE_WEBSOCKET_UPGRADE_HEADER_VALUE = "websocket"; + + String TRIPLE_WEBSOCKET_REMOTE_ADDRESS = "tri.websocket.remote.address"; + + String TRIPLE_WEBSOCKET_LISTENER = "tri.websocket.listener"; +} diff --git a/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/WebSocketStreamChannel.java b/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/WebSocketStreamChannel.java new file mode 100644 index 00000000000..a92235883a6 --- /dev/null +++ b/dubbo-plugin/dubbo-triple-websocket/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/WebSocketStreamChannel.java @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.dubbo.rpc.protocol.tri.websocket; + +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.config.nested.TripleConfig; +import org.apache.dubbo.remoting.http12.HttpHeaderNames; +import org.apache.dubbo.remoting.http12.HttpHeaders; +import org.apache.dubbo.remoting.http12.HttpMetadata; +import org.apache.dubbo.remoting.http12.HttpOutputMessage; +import org.apache.dubbo.remoting.http12.HttpStatus; +import org.apache.dubbo.remoting.http12.LimitedByteArrayOutputStream; +import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; +import org.apache.dubbo.remoting.http12.h2.Http2Header; +import org.apache.dubbo.remoting.http12.h2.Http2OutputMessage; +import org.apache.dubbo.remoting.http12.h2.Http2OutputMessageFrame; +import org.apache.dubbo.remoting.websocket.WebSocketHeaderNames; + +import javax.websocket.CloseReason; +import javax.websocket.Session; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +import static org.apache.dubbo.rpc.protocol.tri.websocket.WebSocketConstants.TRIPLE_WEBSOCKET_REMOTE_ADDRESS; + +public class WebSocketStreamChannel implements H2StreamChannel { + + private final Session session; + + private final TripleConfig tripleConfig; + + private final InetSocketAddress remoteAddress; + + private final InetSocketAddress localAddress; + + public WebSocketStreamChannel(Session session, TripleConfig tripleConfig) { + this.session = session; + this.tripleConfig = tripleConfig; + Map> requestParameterMap = session.getRequestParameterMap(); + List remoteAddressData = requestParameterMap.get(TRIPLE_WEBSOCKET_REMOTE_ADDRESS); + this.remoteAddress = InetSocketAddress.createUnresolved( + remoteAddressData.get(0), Integer.parseInt(remoteAddressData.get(1))); + this.localAddress = InetSocketAddress.createUnresolved( + session.getRequestURI().getHost(), session.getRequestURI().getPort()); + } + + @Override + public CompletableFuture writeResetFrame(long errorCode) { + CompletableFuture completableFuture = new CompletableFuture<>(); + try { + session.close(); + completableFuture.complete(null); + } catch (IOException e) { + completableFuture.completeExceptionally(e); + } + return completableFuture; + } + + @Override + public Http2OutputMessage newOutputMessage(boolean endStream) { + return new Http2OutputMessageFrame( + new LimitedByteArrayOutputStream(256, tripleConfig.getMaxResponseBodySizeOrDefault()), endStream); + } + + @Override + public CompletableFuture writeHeader(HttpMetadata httpMetadata) { + Http2Header http2Header = (Http2Header) httpMetadata; + CompletableFuture completableFuture = new CompletableFuture<>(); + if (http2Header.isEndStream()) { + try { + session.close(encodeCloseReason(http2Header)); + completableFuture.complete(null); + } catch (IOException e) { + completableFuture.completeExceptionally(e); + } + } + return completableFuture; + } + + @Override + public CompletableFuture writeMessage(HttpOutputMessage httpOutputMessage) { + ByteArrayOutputStream body = (ByteArrayOutputStream) httpOutputMessage.getBody(); + CompletableFuture completableFuture = new CompletableFuture<>(); + try { + session.getBasicRemote().sendBinary(ByteBuffer.wrap(body.toByteArray())); + completableFuture.complete(null); + } catch (IOException e) { + completableFuture.completeExceptionally(e); + } + return completableFuture; + } + + @Override + public SocketAddress remoteAddress() { + return remoteAddress; + } + + @Override + public SocketAddress localAddress() { + return localAddress; + } + + @Override + public void flush() {} + + private CloseReason encodeCloseReason(Http2Header http2Header) { + HttpHeaders headers = http2Header.headers(); + List statusHeaders = headers.remove(HttpHeaderNames.STATUS.getName()); + CloseReason closeReason; + if (CollectionUtils.isNotEmpty(statusHeaders) + && !HttpStatus.OK.getStatusString().equals(statusHeaders.get(0))) { + List messageHeaders = headers.remove(WebSocketHeaderNames.WEBSOCKET_MESSAGE.getName()); + closeReason = new CloseReason( + CloseReason.CloseCodes.UNEXPECTED_CONDITION, + CollectionUtils.isNotEmpty(messageHeaders) ? messageHeaders.get(0) : "Internal server error"); + } else { + closeReason = new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "Bye"); + } + return closeReason; + } +} diff --git a/dubbo-plugin/pom.xml b/dubbo-plugin/pom.xml deleted file mode 100644 index 1cfb0efb141..00000000000 --- a/dubbo-plugin/pom.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - - 4.0.0 - - org.apache.dubbo - dubbo-parent - ${revision} - ../pom.xml - - - dubbo-plugin - pom - - dubbo-plugin - The plugins of dubbo project - - dubbo-qos - dubbo-auth - dubbo-reactive - dubbo-security - dubbo-spring-security - dubbo-qos-api - dubbo-native - dubbo-compiler - dubbo-filter-cache - dubbo-filter-validation - dubbo-rest-jaxrs - dubbo-rest-spring - dubbo-triple-servlet - - - false - - - - - org.apache.dubbo - dubbo-test-check - ${project.parent.version} - test - - - org.apache.logging.log4j - log4j-slf4j-impl - test - - - - - - loom - - [21,) - - - dubbo-plugin-loom - - - - release - - dubbo-plugin-loom - - - - diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/RegistryScopeModelInitializer.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/RegistryScopeModelInitializer.java index 3c60a08cba7..9cb22fa8a53 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/RegistryScopeModelInitializer.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/RegistryScopeModelInitializer.java @@ -22,10 +22,10 @@ import org.apache.dubbo.registry.support.RegistryManager; import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; public class RegistryScopeModelInitializer implements ScopeModelInitializer { + @Override public void initializeFrameworkModel(FrameworkModel frameworkModel) { ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory(); @@ -38,7 +38,4 @@ public void initializeApplicationModel(ApplicationModel applicationModel) { beanFactory.registerBean(RegistryManager.class); beanFactory.registerBean(MetadataServiceDelegation.class); } - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java index b86afee87d4..f84255abeb7 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java @@ -211,8 +211,12 @@ public void doSubscribe(URL url, NotifyListener listener) { mappingLock.lock(); mappingByUrl = serviceNameMapping.getMapping(url); try { - MappingListener mappingListener = new DefaultMappingListener(url, mappingByUrl, listener); + DefaultMappingListener mappingListener = new DefaultMappingListener(url, mappingByUrl, listener); mappingByUrl = serviceNameMapping.getAndListen(this.getUrl(), url, mappingListener); + // update the initial mapping apps we started to listen, to make sure it reflects the real value + // used do subscription before any event. + // it's protected by the mapping lock, so it won't override the event value. + mappingListener.updateInitialApps(mappingByUrl); synchronized (mappingListeners) { mappingListeners .computeIfAbsent(url.getProtocolServiceKey(), (k) -> new ConcurrentHashSet<>()) @@ -399,8 +403,8 @@ public Map getServiceListeners() { private class DefaultMappingListener implements MappingListener { private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(DefaultMappingListener.class); private final URL url; - private Set oldApps; - private NotifyListener listener; + private final NotifyListener listener; + private volatile Set oldApps; private volatile boolean stopped; public DefaultMappingListener(URL subscribedURL, Set serviceNames, NotifyListener listener) { @@ -424,16 +428,15 @@ public synchronized void onEvent(MappingChangedEvent event) { Set newApps = event.getApps(); Set tempOldApps = oldApps; - if (CollectionUtils.isEmpty(newApps) || CollectionUtils.equals(newApps, tempOldApps)) { - return; - } - - logger.info( - "Mapping of service " + event.getServiceKey() + "changed from " + tempOldApps + " to " + newApps); - Lock mappingLock = serviceNameMapping.getMappingLock(event.getServiceKey()); try { mappingLock.lock(); + if (CollectionUtils.isEmpty(newApps) || CollectionUtils.equals(newApps, tempOldApps)) { + return; + } + logger.info("Mapping of service " + event.getServiceKey() + "changed from " + tempOldApps + " to " + + newApps); + if (CollectionUtils.isEmpty(tempOldApps) && !newApps.isEmpty()) { serviceNameMapping.putCachedMapping(ServiceNameMapping.buildMappingKey(url), newApps); subscribeURLs(url, listener, newApps); @@ -456,6 +459,7 @@ public synchronized void onEvent(MappingChangedEvent event) { oldListener.removeListener(url.getServiceKey(), listener); if (!oldListener.hasListeners()) { oldListener.destroy(); + serviceListeners.remove(appKey); removeAppSubscriptionLock(appKey); } } finally { @@ -477,6 +481,14 @@ protected NotifyListener getListener() { return listener; } + // writing of oldApps is protected by mapping lock to guarantee sequence consistency. + public void updateInitialApps(Set oldApps) { + if (oldApps != null && !CollectionUtils.equals(oldApps, this.oldApps)) { + this.oldApps = oldApps; + logger.info("Update initial mapping apps from " + this.oldApps + " to " + oldApps); + } + } + @Override public void stop() { stopped = true; diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistryDirectory.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistryDirectory.java index 74c35a746d4..d77c72bbc9d 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistryDirectory.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistryDirectory.java @@ -72,6 +72,7 @@ import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY; import static org.apache.dubbo.common.constants.CommonConstants.INSTANCE_REGISTER_MODE; import static org.apache.dubbo.common.constants.CommonConstants.IS_EXTRA; +import static org.apache.dubbo.common.constants.CommonConstants.PREFERRED_PROTOCOL; import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY; import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY; import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_DESTROY_INVOKER; @@ -447,23 +448,12 @@ private Map> toInvokers( } // filter all the service available (version wildcard, group wildcard, protocol wildcard) - int port = instanceAddressURL.getPort(); List matchedProtocolServiceKeys = - instanceAddressURL.getMetadataInfo().getMatchedServiceInfos(consumerProtocolServiceKey).stream() - .filter(serviceInfo -> serviceInfo.getPort() <= 0 || serviceInfo.getPort() == port) - // special filter for extra protocols. - .filter(serviceInfo -> { - if (StringUtils.isNotEmpty( - consumerProtocolServiceKey - .getProtocol())) { // if consumer side protocol is specified, use all - // the protocols we got in hand now directly - return true; - } else { // if consumer side protocol is not specified, remove all extra protocols - return StringUtils.isEmpty(serviceInfo.getParameter(IS_EXTRA)); - } - }) - .map(MetadataInfo.ServiceInfo::getProtocolServiceKey) - .collect(Collectors.toList()); + getMatchedProtocolServiceKeys(instanceAddressURL, true); + if (CollectionUtils.isEmpty(matchedProtocolServiceKeys)) { + // if preferred protocol is not specified, use the default main protocol + matchedProtocolServiceKeys = getMatchedProtocolServiceKeys(instanceAddressURL, false); + } // see org.apache.dubbo.common.ProtocolServiceKey.isSameWith // check if needed to override the consumer url @@ -524,6 +514,31 @@ private Map> toInvokers( return newUrlInvokerMap; } + private List getMatchedProtocolServiceKeys( + InstanceAddressURL instanceAddressURL, boolean needPreferred) { + int port = instanceAddressURL.getPort(); + return instanceAddressURL.getMetadataInfo().getMatchedServiceInfos(consumerProtocolServiceKey).stream() + .filter(serviceInfo -> serviceInfo.getPort() <= 0 || serviceInfo.getPort() == port) + // special filter for extra protocols. + .filter(serviceInfo -> { + if (StringUtils.isNotEmpty( + consumerProtocolServiceKey + .getProtocol())) { // if consumer side protocol is specified, use all + // the protocols we got in hand now directly + return true; + } else { + // if consumer side protocol is not specified, choose the preferred or default main protocol + if (needPreferred) { + return serviceInfo.getProtocol().equals(serviceInfo.getParameter(PREFERRED_PROTOCOL)); + } else { + return StringUtils.isEmpty(serviceInfo.getParameter(IS_EXTRA)); + } + } + }) + .map(MetadataInfo.ServiceInfo::getProtocolServiceKey) + .collect(Collectors.toList()); + } + private boolean urlChanged(Invoker invoker, InstanceAddressURL newURL, ProtocolServiceKey protocolServiceKey) { InstanceAddressURL oldURL = (InstanceAddressURL) invoker.getUrl(); diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListener.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListener.java index ba5e7ac8035..78362506dd8 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListener.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/event/listener/ServiceInstancesChangedListener.java @@ -182,28 +182,8 @@ private synchronized void doOnEvent(ServiceInstancesChangedEvent event) { } int emptyNum = hasEmptyMetadata(revisionToInstances); - if (emptyNum != 0) { // retry every 10 seconds + if (emptyNum != 0) { hasEmptyMetadata = true; - if (retryPermission.tryAcquire()) { - if (retryFuture != null && !retryFuture.isDone()) { - // cancel last retryFuture because only one retryFuture will be canceled at destroy(). - retryFuture.cancel(true); - } - try { - retryFuture = scheduler.schedule( - new AddressRefreshRetryTask(retryPermission, event.getServiceName()), - 10_000L, - TimeUnit.MILLISECONDS); - } catch (Exception e) { - logger.error( - INTERNAL_ERROR, - "unknown error in registry module", - "", - "Error submitting async retry task."); - } - logger.warn( - INTERNAL_ERROR, "unknown error in registry module", "", "Address refresh try task submitted"); - } // return if all metadata is empty, this notification will not take effect. if (emptyNum == revisionToInstances.size()) { @@ -214,10 +194,12 @@ private synchronized void doOnEvent(ServiceInstancesChangedEvent event) { "", "Address refresh failed because of Metadata Server failure, wait for retry or new address refresh event."); + submitRetryTask(event); return; } + } else { + hasEmptyMetadata = false; } - hasEmptyMetadata = false; Map, Object>>> protocolRevisionsToUrls = new HashMap<>(); Map> newServiceUrls = new HashMap<>(); @@ -241,6 +223,30 @@ private synchronized void doOnEvent(ServiceInstancesChangedEvent event) { this.serviceUrls = newServiceUrls; this.notifyAddressChanged(); + + if (hasEmptyMetadata) { + submitRetryTask(event); + } + } + + private void submitRetryTask(ServiceInstancesChangedEvent event) { + // retry every 10 seconds + if (retryPermission.tryAcquire()) { + if (retryFuture != null && !retryFuture.isDone()) { + // cancel last retryFuture because only one retryFuture will be canceled at destroy(). + retryFuture.cancel(true); + } + try { + retryFuture = scheduler.schedule( + new AddressRefreshRetryTask(retryPermission, event.getServiceName()), + 10_000L, + TimeUnit.MILLISECONDS); + } catch (Exception e) { + logger.error( + INTERNAL_ERROR, "unknown error in registry module", "", "Error submitting async retry task."); + } + logger.warn(INTERNAL_ERROR, "unknown error in registry module", "", "Address refresh try task submitted"); + } } public synchronized void addListenerAndNotify(URL url, NotifyListener listener) { diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java index 55041f96e88..eae0eb90e58 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java @@ -26,7 +26,12 @@ import org.apache.dubbo.metadata.MetadataService; import org.apache.dubbo.registry.client.ServiceDiscovery; import org.apache.dubbo.registry.support.RegistryManager; +import org.apache.dubbo.remoting.http12.HttpStatus; +import org.apache.dubbo.remoting.http12.exception.HttpStatusException; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; +import org.apache.dubbo.remoting.http12.rest.OpenAPIService; import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.rpc.protocol.tri.TripleProtocol; import java.util.ArrayList; import java.util.Comparator; @@ -55,7 +60,7 @@ public class MetadataServiceDelegation implements MetadataService, Disposable { private final ApplicationModel applicationModel; private final RegistryManager registryManager; - private ConcurrentMap instanceMetadataChangedListenerMap = + private final ConcurrentMap instanceMetadataChangedListenerMap = new ConcurrentHashMap<>(); private URL url; // works only for DNS service discovery @@ -214,6 +219,18 @@ public String getAndListenInstanceMetadata(String consumerId, InstanceMetadataCh return instanceMetadata; } + @Override + public String getOpenAPI(OpenAPIRequest request) { + if (TripleProtocol.OPENAPI_ENABLED) { + OpenAPIService openAPIService = applicationModel.getBean(OpenAPIService.class); + if (openAPIService != null) { + return openAPIService.getDocument(request); + } + } + + throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode(), "OpenAPI is not available"); + } + private SortedSet getServiceURLs( Map> exportedServiceURLs, String serviceKey, String protocol) { diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegationV2.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegationV2.java index 10878cce00d..9bf263e7767 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegationV2.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegationV2.java @@ -23,9 +23,17 @@ import org.apache.dubbo.metadata.DubboMetadataServiceV2Triple.MetadataServiceV2ImplBase; import org.apache.dubbo.metadata.MetadataInfo; import org.apache.dubbo.metadata.MetadataRequest; +import org.apache.dubbo.metadata.OpenAPIFormat; +import org.apache.dubbo.metadata.OpenAPIInfo; import org.apache.dubbo.registry.client.ServiceDiscovery; import org.apache.dubbo.registry.support.RegistryManager; +import org.apache.dubbo.remoting.http12.HttpStatus; +import org.apache.dubbo.remoting.http12.exception.HttpStatusException; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; +import org.apache.dubbo.remoting.http12.rest.OpenAPIService; import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.TripleProtocol; import static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_LOAD_METADATA; import static org.apache.dubbo.metadata.util.MetadataServiceVersionUtils.toV2; @@ -34,8 +42,7 @@ public class MetadataServiceDelegationV2 extends MetadataServiceV2ImplBase { ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass()); - private final ApplicationModel applicationModel; - + private final FrameworkModel frameworkModel; private final RegistryManager registryManager; private URL metadataUrl; @@ -43,14 +50,14 @@ public class MetadataServiceDelegationV2 extends MetadataServiceV2ImplBase { public static final String VERSION = "2.0.0"; public MetadataServiceDelegationV2(ApplicationModel applicationModel) { - this.applicationModel = applicationModel; - this.registryManager = RegistryManager.getInstance(applicationModel); + frameworkModel = applicationModel.getFrameworkModel(); + registryManager = RegistryManager.getInstance(applicationModel); } @Override public org.apache.dubbo.metadata.MetadataInfoV2 getMetadataInfo(MetadataRequest metadataRequestV2) { String revision = metadataRequestV2.getRevision(); - MetadataInfo info = null; + MetadataInfo info; if (StringUtils.isEmpty(revision)) { return null; } @@ -70,6 +77,32 @@ public org.apache.dubbo.metadata.MetadataInfoV2 getMetadataInfo(MetadataRequest return null; } + @Override + public OpenAPIInfo getOpenAPIInfo(org.apache.dubbo.metadata.OpenAPIRequest request) { + if (TripleProtocol.OPENAPI_ENABLED) { + OpenAPIService openAPIService = frameworkModel.getBean(OpenAPIService.class); + if (openAPIService != null) { + OpenAPIRequest oRequest = new OpenAPIRequest(); + oRequest.setGroup(request.getGroup()); + oRequest.setVersion(request.getVersion()); + oRequest.setTag(request.getTagList().toArray(StringUtils.EMPTY_STRING_ARRAY)); + oRequest.setService(request.getServiceList().toArray(StringUtils.EMPTY_STRING_ARRAY)); + oRequest.setOpenapi(request.getOpenapi()); + OpenAPIFormat format = request.getFormat(); + if (request.hasFormat()) { + oRequest.setFormat(format.name()); + } + if (request.hasPretty()) { + oRequest.setPretty(request.getPretty()); + } + String document = openAPIService.getDocument(oRequest); + return OpenAPIInfo.newBuilder().setDefinition(document).build(); + } + } + + throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode(), "OpenAPI is not available"); + } + public URL getMetadataUrl() { return metadataUrl; } diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceNameMapping.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceNameMapping.java index 57c7dd51d36..6db3dd7d217 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceNameMapping.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceNameMapping.java @@ -130,7 +130,7 @@ public boolean map(URL url) { + waitTime + ". " + "Service Interface: " + serviceInterface + ". " + "Origin Content: " + oldConfigContent + ". " + "Ticket: " - + configItem.getTicket() + ". " + "Excepted context: " + + configItem.getTicket() + ". " + "Expected Content: " + newConfigContent); Thread.sleep(waitTime); } diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataUtils.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataUtils.java index 2336b61d17a..663d213247e 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataUtils.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataUtils.java @@ -53,6 +53,7 @@ import java.util.Map; import java.util.concurrent.ThreadLocalRandom; +import static org.apache.dubbo.common.constants.CommonConstants.CHECK_KEY; import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE; import static org.apache.dubbo.common.constants.CommonConstants.FILTER_KEY; import static org.apache.dubbo.common.constants.CommonConstants.NATIVE_STUB; @@ -233,6 +234,7 @@ private static URL buildMetadataUrl(ServiceInstance instance) { String version = metadata.get(METADATA_SERVICE_VERSION_NAME); url = url.putAttribute(METADATA_SERVICE_VERSION_NAME, version); + url = url.addParameter(CHECK_KEY, false); return url; } diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceMetadataUtils.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceMetadataUtils.java index ac10fd5835f..ba84044c45a 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceMetadataUtils.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceMetadataUtils.java @@ -218,7 +218,7 @@ public static void registerMetadataAndInstance(ApplicationModel applicationModel applicationModel, Collections.singletonList(getServiceDiscoveryName(serviceDiscovery))), () -> { // register service instance - serviceDiscoveries.forEach(ServiceDiscovery::register); + serviceDiscovery.register(); return null; }); } diff --git a/dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/util/CuratorFrameworkUtils.java b/dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/util/CuratorFrameworkUtils.java index c373e2983ad..19da7748aff 100644 --- a/dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/util/CuratorFrameworkUtils.java +++ b/dubbo-registry/dubbo-registry-zookeeper/src/main/java/org/apache/dubbo/registry/zookeeper/util/CuratorFrameworkUtils.java @@ -45,6 +45,7 @@ import static org.apache.curator.x.discovery.ServiceInstance.builder; import static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR; +import static org.apache.dubbo.common.constants.CommonConstants.SESSION_KEY; import static org.apache.dubbo.common.constants.CommonConstants.ZOOKEEPER_ENSEMBLE_TRACKER_KEY; import static org.apache.dubbo.registry.zookeeper.ZookeeperServiceDiscovery.DEFAULT_GROUP; import static org.apache.dubbo.registry.zookeeper.util.CuratorFrameworkParams.BASE_SLEEP_TIME; @@ -62,6 +63,8 @@ */ public abstract class CuratorFrameworkUtils { + protected static int DEFAULT_SESSION_TIMEOUT_MS = 60 * 1000; + public static ServiceDiscovery buildServiceDiscovery( CuratorFramework curatorFramework, String basePath) { return ServiceDiscoveryBuilder.builder(ZookeeperInstance.class) @@ -72,8 +75,10 @@ public static ServiceDiscovery buildServiceDiscovery( public static CuratorFramework buildCuratorFramework(URL connectionURL, ZookeeperServiceDiscovery serviceDiscovery) throws Exception { + int sessionTimeoutMs = connectionURL.getParameter(SESSION_KEY, DEFAULT_SESSION_TIMEOUT_MS); CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder() .connectString(connectionURL.getBackupAddress()) + .sessionTimeoutMs(sessionTimeoutMs) .retryPolicy(buildRetryPolicy(connectionURL)); try { // use reflect to check method exist to compatibility with curator4, can remove in dubbo3.3 and direct call diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/connection/AbstractConnectionClient.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/connection/AbstractConnectionClient.java index 80aa710a28f..c6f7d40f375 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/connection/AbstractConnectionClient.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/connection/AbstractConnectionClient.java @@ -17,8 +17,6 @@ package org.apache.dubbo.remoting.api.connection; import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; -import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.remoting.ChannelHandler; import org.apache.dubbo.remoting.RemotingException; import org.apache.dubbo.remoting.api.WireProtocol; @@ -32,9 +30,6 @@ public abstract class AbstractConnectionClient extends AbstractClient { - private static final ErrorTypeAwareLogger logger = - LoggerFactory.getErrorTypeAwareLogger(AbstractConnectionClient.class); - protected WireProtocol protocol; protected InetSocketAddress remote; @@ -61,13 +56,17 @@ public final void increase() { /** * Increments the reference count by 1. */ - public final AbstractConnectionClient retain() { + public final boolean retain() { long oldCount = COUNTER_UPDATER.getAndIncrement(this); if (oldCount <= 0) { COUNTER_UPDATER.getAndDecrement(this); - throw new AssertionError("This instance has been destroyed"); + logger.info( + "Retain failed, because connection " + remote + + " has been destroyed but not yet removed, will create a new one instead." + + " Check logs below to confirm that this connection finally gets removed to make sure there's no potential memory leak!"); + return false; } - return this; + return true; } /** @@ -77,6 +76,7 @@ public boolean release() { long remainingCount = COUNTER_UPDATER.decrementAndGet(this); if (remainingCount == 0) { + logger.info("Destroying connection to {}, because the reference count reaches 0", remote); destroy(); return true; } else if (remainingCount <= -1) { diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/connection/SingleProtocolConnectionManager.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/connection/SingleProtocolConnectionManager.java index 3f840696710..10f002df619 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/connection/SingleProtocolConnectionManager.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/api/connection/SingleProtocolConnectionManager.java @@ -17,6 +17,8 @@ package org.apache.dubbo.remoting.api.connection; import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; +import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.remoting.ChannelHandler; import org.apache.dubbo.remoting.Constants; import org.apache.dubbo.rpc.model.FrameworkModel; @@ -26,6 +28,9 @@ import java.util.function.Consumer; public class SingleProtocolConnectionManager implements ConnectionManager { + private static final ErrorTypeAwareLogger logger = + LoggerFactory.getErrorTypeAwareLogger(SingleProtocolConnectionManager.class); + public static final String NAME = "single"; private final ConcurrentMap connections = new ConcurrentHashMap<>(16); @@ -42,21 +47,34 @@ public AbstractConnectionClient connect(URL url, ChannelHandler handler) { throw new IllegalArgumentException("url == null"); } return connections.compute(url.getAddress(), (address, conn) -> { + String transport = url.getParameter(Constants.TRANSPORTER_KEY, "netty4"); if (conn == null) { - String transport = url.getParameter(Constants.TRANSPORTER_KEY, "netty4"); - ConnectionManager manager = frameworkModel - .getExtensionLoader(ConnectionManager.class) - .getExtension(transport); - final AbstractConnectionClient connectionClient = manager.connect(url, handler); - connectionClient.addCloseListener(() -> connections.remove(address, connectionClient)); - return connectionClient; + return createAbstractConnectionClient(url, handler, address, transport); } else { - conn.retain(); + boolean shouldReuse = conn.retain(); + if (!shouldReuse) { + logger.info("Trying to create a new connection for {}.", address); + return createAbstractConnectionClient(url, handler, address, transport); + } return conn; } }); } + private AbstractConnectionClient createAbstractConnectionClient( + URL url, ChannelHandler handler, String address, String transport) { + ConnectionManager manager = + frameworkModel.getExtensionLoader(ConnectionManager.class).getExtension(transport); + final AbstractConnectionClient connectionClient = manager.connect(url, handler); + connectionClient.addCloseListener(() -> { + logger.info( + "Remove closed connection (with reference count==0) for address {}, a new one will be created for upcoming RPC requests routing to this address.", + address); + connections.remove(address, connectionClient); + }); + return connectionClient; + } + @Override public void forEachConnection(Consumer connectionConsumer) { connections.values().forEach(connectionConsumer); diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractClient.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractClient.java index c26d9352f49..5b842d33aff 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractClient.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractClient.java @@ -18,8 +18,6 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.Version; -import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; -import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.threadpool.manager.ExecutorRepository; import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository; import org.apache.dubbo.common.utils.NetUtils; @@ -55,8 +53,6 @@ */ public abstract class AbstractClient extends AbstractEndpoint implements Client { - private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(AbstractClient.class); - private final Lock connectLock = new ReentrantLock(); private final boolean needReconnect; @@ -148,7 +144,7 @@ protected AbstractClient() { private void initExecutor(URL url) { ExecutorRepository executorRepository = ExecutorRepository.getInstance(url.getOrDefaultApplicationModel()); - /** + /* * Consumer's executor is shared globally, provider ip doesn't need to be part of the thread name. * * Instance of url is InstanceAddressURL, so addParameter actually adds parameters into ServiceInstance, @@ -415,36 +411,26 @@ public String toString() { /** * Open client. - * - * @throws Throwable */ protected abstract void doOpen() throws Throwable; /** * Close client. - * - * @throws Throwable */ protected abstract void doClose() throws Throwable; /** * Connect to server. - * - * @throws Throwable */ protected abstract void doConnect() throws Throwable; /** * disConnect to server. - * - * @throws Throwable */ protected abstract void doDisConnect() throws Throwable; /** * Get the connected channel. - * - * @return channel */ protected abstract Channel getChannel(); } diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractEndpoint.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractEndpoint.java index cc199265d69..c5cf86996f7 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractEndpoint.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractEndpoint.java @@ -36,7 +36,7 @@ */ public abstract class AbstractEndpoint extends AbstractPeer implements Resetable { - private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(AbstractEndpoint.class); + protected final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass()); private Codec2 codec; diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractServer.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractServer.java index bb50ddc304d..1977d2b52ff 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractServer.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractServer.java @@ -17,8 +17,6 @@ package org.apache.dubbo.remoting.transport; import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; -import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.threadpool.manager.ExecutorRepository; import org.apache.dubbo.common.utils.ConcurrentHashSet; import org.apache.dubbo.common.utils.ExecutorUtil; @@ -45,7 +43,7 @@ * AbstractServer */ public abstract class AbstractServer extends AbstractEndpoint implements RemotingServer { - private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(AbstractServer.class); + private Set executors = new ConcurrentHashSet<>(); private InetSocketAddress localAddress; private InetSocketAddress bindAddress; diff --git a/dubbo-remoting/dubbo-remoting-http12/pom.xml b/dubbo-remoting/dubbo-remoting-http12/pom.xml index c81f5ae601a..4d16603471c 100644 --- a/dubbo-remoting/dubbo-remoting-http12/pom.xml +++ b/dubbo-remoting/dubbo-remoting-http12/pom.xml @@ -46,10 +46,6 @@ dubbo-remoting-api ${project.parent.version} - - com.google.protobuf - protobuf-java-util - io.netty @@ -60,6 +56,12 @@ netty-codec-http2 + + com.google.protobuf + protobuf-java-util + provided + + javax.xml.bind jaxb-api diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java index 1c7cf43cc47..e6c4277bb44 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java @@ -21,6 +21,7 @@ import org.apache.dubbo.remoting.http12.exception.HttpStatusException; import org.apache.dubbo.remoting.http12.message.HttpMessageEncoder; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.function.BiConsumer; @@ -96,7 +97,14 @@ public final void onNext(Object data) { doOnNext(data); } catch (Throwable t) { LOGGER.warn(INTERNAL_ERROR, "", "", "Error while doOnNext", t); - onError(t); + Throwable throwable = t; + try { + doOnError(throwable); + } catch (Throwable t1) { + LOGGER.warn(INTERNAL_ERROR, "", "", "Error while doOnError, original error: " + throwable, t1); + throwable = t1; + } + onCompleted(throwable); } } @@ -105,7 +113,6 @@ public final void onError(Throwable throwable) { if (closed) { return; } - try { throwable = customizeError(throwable); if (throwable == null) { @@ -122,7 +129,6 @@ public final void onError(Throwable throwable) { LOGGER.warn(INTERNAL_ERROR, "", "", "Error while doOnError, original error: " + throwable, t); throwable = t; } - onCompleted(throwable); } @@ -163,7 +169,7 @@ protected final HttpMetadata buildMetadata( if (data instanceof HttpResult) { HttpResult result = (HttpResult) data; if (result.getHeaders() != null) { - headers.add(result.getHeaders()); + headers.set(result.getHeaders()); } } customizeHeaders(headers, throwable, message); @@ -202,7 +208,13 @@ protected final HttpOutputMessage buildMessage(int statusCode, Object data) thro if (LOGGER.isDebugEnabled()) { try { - LOGGER.debug("Http response body sent: '{}' by [{}]", JsonUtils.toJson(data), httpChannel); + String text; + if (data instanceof byte[]) { + text = new String((byte[]) data, StandardCharsets.UTF_8); + } else { + text = JsonUtils.toJson(data); + } + LOGGER.debug("Http response body sent: '{}' by [{}]", text, httpChannel); } catch (Throwable ignored) { } } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpConstants.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpConstants.java index a45e8fe396a..ef6995b8579 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpConstants.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpConstants.java @@ -16,12 +16,16 @@ */ package org.apache.dubbo.remoting.http12; +import java.nio.charset.StandardCharsets; + public final class HttpConstants { public static final String TRAILERS = "trailers"; public static final String CHUNKED = "chunked"; + public static final String NO_CACHE = "no-cache"; + public static final String X_FORWARDED_PROTO = "x-forwarded-proto"; public static final String X_FORWARDED_HOST = "x-forwarded-host"; public static final String X_FORWARDED_PORT = "x-forwarded-port"; @@ -29,5 +33,8 @@ public final class HttpConstants { public static final String HTTPS = "https"; public static final String HTTP = "http"; + public static final byte[] SERVER_SENT_EVENT_DATA_PREFIX_BYTES = "data:".getBytes(StandardCharsets.US_ASCII); + public static final byte[] SERVER_SENT_EVENT_LF_BYTES = "\n\n".getBytes(StandardCharsets.US_ASCII); + private HttpConstants() {} } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpHeaderNames.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpHeaderNames.java index 0abfb8658fc..a701870f73d 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpHeaderNames.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpHeaderNames.java @@ -24,6 +24,8 @@ public enum HttpHeaderNames { PATH(PseudoHeaderName.PATH.value()), + METHOD(PseudoHeaderName.METHOD.value()), + ACCEPT(io.netty.handler.codec.http.HttpHeaderNames.ACCEPT), CONTENT_TYPE(io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE), @@ -34,6 +36,8 @@ public enum HttpHeaderNames { TRANSFER_ENCODING(io.netty.handler.codec.http.HttpHeaderNames.TRANSFER_ENCODING), + CACHE_CONTROL(io.netty.handler.codec.http.HttpHeaderNames.CACHE_CONTROL), + LOCATION(io.netty.handler.codec.http.HttpHeaderNames.LOCATION), HOST(io.netty.handler.codec.http.HttpHeaderNames.HOST), diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpMetadata.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpMetadata.java index acf8a5d171c..48cdf456332 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpMetadata.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpMetadata.java @@ -27,4 +27,9 @@ default String contentType() { default String header(CharSequence name) { return headers().getFirst(name); } + + default HttpMetadata header(CharSequence name, String value) { + headers().set(name, value); + return this; + } } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpMethods.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpMethods.java index 5b9644e5c39..0388606dfcd 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpMethods.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpMethods.java @@ -43,6 +43,10 @@ public boolean is(String name) { return name().equals(name); } + public boolean supportBody() { + return this == POST || this == PUT || this == PATCH; + } + @SuppressWarnings("StringEquality") public static HttpMethods of(String name) { // fast-path diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpUtils.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpUtils.java index 22e16fb20f7..40383e3d977 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpUtils.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpUtils.java @@ -29,8 +29,10 @@ import java.util.Locale; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.ByteBufInputStream; -import io.netty.buffer.Unpooled; +import io.netty.buffer.ByteBufOutputStream; +import io.netty.buffer.UnpooledByteBufAllocator; import io.netty.handler.codec.http.DefaultFullHttpRequest; import io.netty.handler.codec.http.DefaultHttpHeaders; import io.netty.handler.codec.http.HttpHeaders; @@ -51,6 +53,7 @@ public final class HttpUtils { + public static final ByteBufAllocator HEAP_ALLOC = new UnpooledByteBufAllocator(false, false); public static final HttpDataFactory DATA_FACTORY = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); public static final String CHARSET_PREFIX = "charset="; @@ -90,10 +93,10 @@ public static String encodeCookie(HttpCookie cookie) { } public static List parseAccept(String header) { - List> mediaTypes = new ArrayList<>(); if (header == null) { - return Collections.emptyList(); + return new ArrayList<>(); } + List> mediaTypes = new ArrayList<>(); for (String item : StringUtils.tokenize(header, ',')) { int index = item.indexOf(';'); mediaTypes.add(new Item<>(StringUtils.substring(item, 0, index), parseQuality(item, index))); @@ -121,10 +124,10 @@ public static float parseQuality(String expr, int index) { } public static List parseAcceptLanguage(String header) { - List> locales = new ArrayList<>(); if (header == null) { - return Collections.emptyList(); + return new ArrayList<>(); } + List> locales = new ArrayList<>(); for (String item : StringUtils.tokenize(header, ',')) { String[] pair = StringUtils.tokenize(item, ';'); locales.add(new Item<>(parseLocale(pair[0]), pair.length > 1 ? Float.parseFloat(pair[1]) : 1.0F)); @@ -133,10 +136,10 @@ public static List parseAcceptLanguage(String header) { } public static List parseContentLanguage(String header) { - List locales = new ArrayList<>(); if (header == null) { - return Collections.emptyList(); + return new ArrayList<>(); } + List locales = new ArrayList<>(); for (String item : StringUtils.tokenize(header, ',')) { locales.add(parseLocale(item)); } @@ -164,7 +167,13 @@ public static HttpPostRequestDecoder createPostRequestDecoder( if (canMark) { inputStream.mark(Integer.MAX_VALUE); } - data = Unpooled.wrappedBuffer(StreamUtils.readBytes(inputStream)); + if (inputStream.available() == 0) { + return null; + } else { + data = HEAP_ALLOC.buffer(); + ByteBufOutputStream os = new ByteBufOutputStream(data); + StreamUtils.copy(inputStream, os); + } } catch (IOException e) { throw new DecodeException("Error while reading post data: " + e.getMessage(), e); } finally { @@ -259,6 +268,9 @@ public int compareTo(Item o) { public static List sortAndGet(List> items) { int size = items.size(); + if (size == 0) { + return Collections.emptyList(); + } if (size == 1) { return Collections.singletonList(items.get(0).value); } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/LimitedByteArrayOutputStream.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/LimitedByteArrayOutputStream.java new file mode 100644 index 00000000000..7596f332ded --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/LimitedByteArrayOutputStream.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.dubbo.remoting.http12; + +import org.apache.dubbo.remoting.http12.exception.HttpOverPayloadException; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public class LimitedByteArrayOutputStream extends ByteArrayOutputStream { + + private final int capacity; + + public LimitedByteArrayOutputStream(int capacity) { + super(); + this.capacity = capacity == 0 ? Integer.MAX_VALUE : capacity; + } + + public LimitedByteArrayOutputStream(int size, int capacity) { + super(size); + this.capacity = capacity == 0 ? Integer.MAX_VALUE : capacity; + } + + @Override + public void write(int b) { + ensureCapacity(1); + super.write(b); + } + + @Override + public void write(byte[] b) throws IOException { + ensureCapacity(b.length); + super.write(b); + } + + @Override + public void write(byte[] b, int off, int len) { + ensureCapacity(len); + super.write(b, off, len); + } + + private void ensureCapacity(int len) { + if (size() + len > capacity) { + throw new HttpOverPayloadException("Response Entity Too Large"); + } + } +} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1ServerStreamChannelObserver.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1SseServerChannelObserver.java similarity index 68% rename from dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1ServerStreamChannelObserver.java rename to dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1SseServerChannelObserver.java index b401075e896..486af06e2a1 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1ServerStreamChannelObserver.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/h1/Http1SseServerChannelObserver.java @@ -19,40 +19,35 @@ import org.apache.dubbo.remoting.http12.HttpChannel; import org.apache.dubbo.remoting.http12.HttpConstants; import org.apache.dubbo.remoting.http12.HttpHeaderNames; -import org.apache.dubbo.remoting.http12.HttpHeaders; import org.apache.dubbo.remoting.http12.HttpMetadata; import org.apache.dubbo.remoting.http12.HttpOutputMessage; import java.io.IOException; -import java.nio.charset.StandardCharsets; -public class Http1ServerStreamChannelObserver extends Http1ServerChannelObserver { +public class Http1SseServerChannelObserver extends Http1ServerChannelObserver { - private static final byte[] SERVER_SENT_EVENT_DATA_PREFIX_BYTES = "data:".getBytes(StandardCharsets.US_ASCII); - private static final byte[] SERVER_SENT_EVENT_LF_BYTES = "\n\n".getBytes(StandardCharsets.US_ASCII); - - public Http1ServerStreamChannelObserver(HttpChannel httpChannel) { + public Http1SseServerChannelObserver(HttpChannel httpChannel) { super(httpChannel); } @Override protected HttpMetadata encodeHttpMetadata(boolean endStream) { - HttpHeaders headers = HttpHeaders.create(); - headers.set(HttpHeaderNames.TRANSFER_ENCODING.getKey(), HttpConstants.CHUNKED); - return new Http1Metadata(headers); + return super.encodeHttpMetadata(endStream) + .header(HttpHeaderNames.TRANSFER_ENCODING.getKey(), HttpConstants.CHUNKED) + .header(HttpHeaderNames.CACHE_CONTROL.getKey(), HttpConstants.NO_CACHE); } @Override protected void preOutputMessage(HttpOutputMessage message) throws IOException { HttpOutputMessage prefixMessage = getHttpChannel().newOutputMessage(); - prefixMessage.getBody().write(SERVER_SENT_EVENT_DATA_PREFIX_BYTES); + prefixMessage.getBody().write(HttpConstants.SERVER_SENT_EVENT_DATA_PREFIX_BYTES); getHttpChannel().writeMessage(prefixMessage); } @Override protected void postOutputMessage(HttpOutputMessage message) throws IOException { HttpOutputMessage lfMessage = getHttpChannel().newOutputMessage(); - lfMessage.getBody().write(SERVER_SENT_EVENT_LF_BYTES); + lfMessage.getBody().write(HttpConstants.SERVER_SENT_EVENT_LF_BYTES); getHttpChannel().writeMessage(lfMessage); } } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpRequest.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpRequest.java index f1909169e69..f3166707b4c 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpRequest.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpRequest.java @@ -287,7 +287,7 @@ public List locales() { if (locales == null) { locales = HttpUtils.parseAcceptLanguage(headers.getFirst(HttpHeaderNames.CONTENT_LANGUAGE.getKey())); if (locales.isEmpty()) { - locales.add(Locale.getDefault()); + locales = Collections.singletonList(Locale.getDefault()); } this.locales = locales; } @@ -300,7 +300,7 @@ public String scheme() { if (isHttp2()) { scheme = headers.getFirst(PseudoHeaderName.SCHEME.value()); } - return scheme == null ? HttpConstants.HTTPS : scheme; + return scheme == null ? HttpConstants.HTTP : scheme; } @Override diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpResponse.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpResponse.java index e5926f8fa0d..9becb189d3d 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpResponse.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpResponse.java @@ -266,8 +266,8 @@ public boolean isContentEmpty() { if (body != null) { return false; } - if (outputStream != null && outputStream instanceof ByteArrayOutputStream) { - return ((ByteArrayOutputStream) outputStream).size() == 0; + if (outputStream != null) { + return outputStream instanceof ByteArrayOutputStream && ((ByteArrayOutputStream) outputStream).size() == 0; } return true; } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpResult.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpResult.java index c7f3ab8df29..8e0f695286a 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpResult.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpResult.java @@ -123,7 +123,7 @@ public Builder headers(HttpHeaders headers) { } Map> hrs = this.headers; if (hrs == null) { - hrs = new LinkedHashMap<>(headers.size()); + this.headers = hrs = new LinkedHashMap<>(headers.size()); } for (Entry entry : headers) { CharSequence key = entry.getKey(); @@ -172,6 +172,10 @@ public Builder addHeader(String key, String value) { return this; } + public Builder contentType(String value) { + return headerIf(HttpHeaderNames.CONTENT_TYPE.getName(), value); + } + public Builder from(HttpResult result) { status = result.getStatus(); headers = result.getHeaders() == null ? null : new LinkedHashMap<>(result.getHeaders()); diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MediaType.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MediaType.java index fd7af730042..1b11e8ec17f 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MediaType.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MediaType.java @@ -16,45 +16,57 @@ */ package org.apache.dubbo.remoting.http12.message; +import java.util.Objects; + public final class MediaType { public static final String WILDCARD = "*"; + public static final String APPLICATION = "application"; + + public static final String TEXT = "text"; + + public static final String JSON = "json"; + + public static final String XML = "xml"; + + public static final String YAML = "yaml"; + public static final MediaType ALL = new MediaType(WILDCARD, WILDCARD); - public static final MediaType APPLICATION_JSON = new MediaType("application", "json"); + public static final MediaType APPLICATION_JSON = new MediaType(APPLICATION, JSON); - public static final MediaType APPLICATION_XML = new MediaType("application", "xml"); + public static final MediaType APPLICATION_XML = new MediaType(APPLICATION, XML); - public static final MediaType APPLICATION_YAML = new MediaType("application", "yaml"); + public static final MediaType APPLICATION_YAML = new MediaType(APPLICATION, YAML); - public static final MediaType APPLICATION_JAVASCRIPT = new MediaType("application", "javascript"); + public static final MediaType APPLICATION_JAVASCRIPT = new MediaType(APPLICATION, "javascript"); - public static final MediaType APPLICATION_OCTET_STREAM = new MediaType("application", "octet-stream"); + public static final MediaType APPLICATION_OCTET_STREAM = new MediaType(APPLICATION, "octet-stream"); - public static final MediaType APPLICATION_GRPC = new MediaType("application", "grpc"); + public static final MediaType APPLICATION_GRPC = new MediaType(APPLICATION, "grpc"); - public static final MediaType APPLICATION_GRPC_PROTO = new MediaType("application", "grpc+proto"); + public static final MediaType APPLICATION_GRPC_PROTO = new MediaType(APPLICATION, "grpc+proto"); - public static final MediaType APPLICATION_FROM_URLENCODED = new MediaType("application", "x-www-form-urlencoded"); + public static final MediaType APPLICATION_FROM_URLENCODED = new MediaType(APPLICATION, "x-www-form-urlencoded"); public static final MediaType MULTIPART_FORM_DATA = new MediaType("multipart", "form-data"); - public static final MediaType TEXT_JSON = new MediaType("text", "json"); + public static final MediaType TEXT_JSON = new MediaType(TEXT, JSON); - public static final MediaType TEXT_XML = new MediaType("text", "xml"); + public static final MediaType TEXT_XML = new MediaType(TEXT, XML); - public static final MediaType TEXT_YAML = new MediaType("text", "yaml"); + public static final MediaType TEXT_YAML = new MediaType(TEXT, YAML); - public static final MediaType TEXT_CSS = new MediaType("text", "css"); + public static final MediaType TEXT_CSS = new MediaType(TEXT, "css"); - public static final MediaType TEXT_JAVASCRIPT = new MediaType("text", "javascript"); + public static final MediaType TEXT_JAVASCRIPT = new MediaType(TEXT, "javascript"); - public static final MediaType TEXT_HTML = new MediaType("text", "html"); + public static final MediaType TEXT_HTML = new MediaType(TEXT, "html"); - public static final MediaType TEXT_PLAIN = new MediaType("text", "plain"); + public static final MediaType TEXT_PLAIN = new MediaType(TEXT, "plain"); - public static final MediaType TEXT_EVENT_STREAM = new MediaType("text", "event-stream"); + public static final MediaType TEXT_EVENT_STREAM = new MediaType(TEXT, "event-stream"); private final String name; @@ -81,6 +93,24 @@ public String getSubType() { } public boolean isPureText() { - return this == TEXT_HTML || this == TEXT_PLAIN; + return TEXT.equals(type); + } + + public static MediaType of(String name) { + Objects.requireNonNull(name); + if (APPLICATION_JSON.name.equals(name)) { + return APPLICATION_JSON; + } + if (APPLICATION_YAML.name.equals(name)) { + return APPLICATION_YAML; + } + if (APPLICATION_FROM_URLENCODED.name.equals(name)) { + return APPLICATION_FROM_URLENCODED; + } + int index = name.indexOf('/'); + if (index > 0) { + return new MediaType(name.substring(0, index), name.substring(index + 1)); + } + throw new IllegalArgumentException("Invalid media type: '" + name + "'"); } } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MethodMetadata.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MethodMetadata.java index 241d0c42bd7..7f87edafbc4 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MethodMetadata.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MethodMetadata.java @@ -21,6 +21,7 @@ import org.apache.dubbo.rpc.model.StubMethodDescriptor; import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; public class MethodMetadata { @@ -64,18 +65,18 @@ private static MethodMetadata doResolveReflection(ReflectionMethodDescriptor met case CLIENT_STREAM: case BI_STREAM: actualRequestTypes = new Class[] { - (Class) - ((ParameterizedType) method.getMethod().getGenericReturnType()).getActualTypeArguments()[0] + obtainActualTypeInStreamObserver( + ((ParameterizedType) method.getMethod().getGenericReturnType()).getActualTypeArguments()[0]) }; - actualResponseType = - (Class) ((ParameterizedType) method.getMethod().getGenericParameterTypes()[0]) - .getActualTypeArguments()[0]; + actualResponseType = obtainActualTypeInStreamObserver( + ((ParameterizedType) method.getMethod().getGenericParameterTypes()[0]) + .getActualTypeArguments()[0]); return new MethodMetadata(actualRequestTypes, actualResponseType); case SERVER_STREAM: actualRequestTypes = new Class[] {method.getMethod().getParameterTypes()[0]}; - actualResponseType = - (Class) ((ParameterizedType) method.getMethod().getGenericParameterTypes()[1]) - .getActualTypeArguments()[0]; + actualResponseType = obtainActualTypeInStreamObserver( + ((ParameterizedType) method.getMethod().getGenericParameterTypes()[1]) + .getActualTypeArguments()[0]); return new MethodMetadata(actualRequestTypes, actualResponseType); case UNARY: actualRequestTypes = method.getParameterClasses(); @@ -84,4 +85,11 @@ private static MethodMetadata doResolveReflection(ReflectionMethodDescriptor met } throw new IllegalStateException("Can not reach here"); } + + static Class obtainActualTypeInStreamObserver(Type typeInStreamObserver) { + return (Class) + (typeInStreamObserver instanceof ParameterizedType + ? ((ParameterizedType) typeInStreamObserver).getRawType() + : typeInStreamObserver); + } } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/BinaryCodecFactory.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/BinaryCodecFactory.java index 354f0c17fb3..ec12d56bfdf 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/BinaryCodecFactory.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/BinaryCodecFactory.java @@ -38,4 +38,9 @@ public HttpMessageCodec createCodec(URL url, FrameworkModel frameworkModel, Stri public MediaType mediaType() { return MediaType.APPLICATION_OCTET_STREAM; } + + @Override + public boolean supports(String mediaType) { + return mediaType.startsWith(MediaType.APPLICATION_OCTET_STREAM.getName()) || mediaType.startsWith("image/"); + } } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/CodecUtils.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/CodecUtils.java index 2b63feb1b09..143857e5fa0 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/CodecUtils.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/CodecUtils.java @@ -17,17 +17,24 @@ package org.apache.dubbo.remoting.http12.message.codec; import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.config.Configuration; +import org.apache.dubbo.common.config.ConfigurationUtils; import org.apache.dubbo.common.utils.Assert; +import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.remoting.http12.exception.UnsupportedMediaTypeException; import org.apache.dubbo.remoting.http12.message.HttpMessageDecoder; import org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory; import org.apache.dubbo.remoting.http12.message.HttpMessageEncoder; import org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory; +import org.apache.dubbo.rpc.Constants; import org.apache.dubbo.rpc.model.FrameworkModel; +import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; public final class CodecUtils { @@ -37,13 +44,18 @@ public final class CodecUtils { private final List encoderFactories; private final Map> encoderCache = new ConcurrentHashMap<>(); private final Map> decoderCache = new ConcurrentHashMap<>(); + private Set disallowedContentTypes = Collections.emptySet(); public CodecUtils(FrameworkModel frameworkModel) { this.frameworkModel = frameworkModel; decoderFactories = frameworkModel.getActivateExtensions(HttpMessageDecoderFactory.class); encoderFactories = frameworkModel.getActivateExtensions(HttpMessageEncoderFactory.class); - decoderFactories.forEach(f -> decoderCache.putIfAbsent(f.mediaType().getName(), Optional.of(f))); - encoderFactories.forEach(f -> encoderCache.putIfAbsent(f.mediaType().getName(), Optional.of(f))); + + Configuration configuration = ConfigurationUtils.getGlobalConfiguration(frameworkModel.defaultApplication()); + String contentTypes = configuration.getString(Constants.H2_SETTINGS_DISALLOWED_CONTENT_TYPES, null); + if (contentTypes != null) { + disallowedContentTypes = new HashSet<>(StringUtils.tokenizeToList(contentTypes)); + } } public HttpMessageDecoder determineHttpMessageDecoder(URL url, String mediaType) { @@ -69,9 +81,10 @@ public HttpMessageEncoder determineHttpMessageEncoder(String mediaType) { public Optional determineHttpMessageDecoderFactory(String mediaType) { Assert.notNull(mediaType, "mediaType must not be null"); return decoderCache.computeIfAbsent(mediaType, k -> { - for (HttpMessageDecoderFactory decoderFactory : decoderFactories) { - if (decoderFactory.supports(k)) { - return Optional.of(decoderFactory); + for (HttpMessageDecoderFactory factory : decoderFactories) { + if (factory.supports(k) + && !disallowedContentTypes.contains(factory.mediaType().getName())) { + return Optional.of(factory); } } return Optional.empty(); @@ -81,9 +94,10 @@ public Optional determineHttpMessageDecoderFactory(St public Optional determineHttpMessageEncoderFactory(String mediaType) { Assert.notNull(mediaType, "mediaType must not be null"); return encoderCache.computeIfAbsent(mediaType, k -> { - for (HttpMessageEncoderFactory encoderFactory : encoderFactories) { - if (encoderFactory.supports(k)) { - return Optional.of(encoderFactory); + for (HttpMessageEncoderFactory factory : encoderFactories) { + if (factory.supports(k) + && !disallowedContentTypes.contains(factory.mediaType().getName())) { + return Optional.of(factory); } } return Optional.empty(); diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/HtmlCodec.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/HtmlCodec.java index 5afc69b028a..378df57d54f 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/HtmlCodec.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/HtmlCodec.java @@ -17,27 +17,43 @@ package org.apache.dubbo.remoting.http12.message.codec; import org.apache.dubbo.common.io.StreamUtils; -import org.apache.dubbo.common.utils.JsonUtils; +import org.apache.dubbo.remoting.http12.HttpJsonUtils; import org.apache.dubbo.remoting.http12.exception.DecodeException; import org.apache.dubbo.remoting.http12.exception.EncodeException; import org.apache.dubbo.remoting.http12.exception.HttpStatusException; import org.apache.dubbo.remoting.http12.message.HttpMessageCodec; import org.apache.dubbo.remoting.http12.message.MediaType; +import org.apache.dubbo.rpc.model.FrameworkModel; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.Charset; -public class HtmlCodec implements HttpMessageCodec { +public final class HtmlCodec implements HttpMessageCodec { + + public static final HtmlCodec INSTANCE = new HtmlCodec(); + + private final HttpJsonUtils httpJsonUtils; + + private HtmlCodec() { + this(FrameworkModel.defaultModel()); + } + + public HtmlCodec(FrameworkModel frameworkModel) { + httpJsonUtils = frameworkModel.getBeanFactory().getOrRegisterBean(HttpJsonUtils.class); + } @Override public void encode(OutputStream os, Object data, Charset charset) throws EncodeException { + if (data == null) { + return; + } try { if (data instanceof CharSequence) { os.write((data.toString()).getBytes(charset)); return; } - os.write(JsonUtils.toJson(data).getBytes(charset)); + os.write(httpJsonUtils.toJson(data).getBytes(charset)); } catch (HttpStatusException e) { throw e; } catch (Throwable t) { diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/HtmlCodecFactory.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/HtmlCodecFactory.java index ee82e05bd03..4d09457121a 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/HtmlCodecFactory.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/HtmlCodecFactory.java @@ -27,11 +27,9 @@ @Activate public final class HtmlCodecFactory implements HttpMessageEncoderFactory, HttpMessageDecoderFactory { - private static final HtmlCodec INSTANCE = new HtmlCodec(); - @Override public HttpMessageCodec createCodec(URL url, FrameworkModel frameworkModel, String mediaType) { - return INSTANCE; + return frameworkModel == FrameworkModel.defaultModel() ? HtmlCodec.INSTANCE : new HtmlCodec(frameworkModel); } @Override diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonPbCodec.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonPbCodec.java index 725dc985e40..502f264e2f2 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonPbCodec.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonPbCodec.java @@ -47,7 +47,8 @@ public JsonPbCodec(FrameworkModel frameworkModel) { public void encode(OutputStream os, Object data, Charset charset) throws EncodeException { try { if (data instanceof Message) { - String jsonString = JsonFormat.printer().print((Message) data); + String jsonString = + JsonFormat.printer().omittingInsignificantWhitespace().print((Message) data); os.write(jsonString.getBytes(charset)); return; } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonPbCodecFactory.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonPbCodecFactory.java index 398225255d0..0a5f63ee919 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonPbCodecFactory.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonPbCodecFactory.java @@ -17,6 +17,7 @@ package org.apache.dubbo.remoting.http12.message.codec; import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.constants.CommonConstants; import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.remoting.http12.message.HttpMessageCodec; import org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory; @@ -24,7 +25,7 @@ import org.apache.dubbo.remoting.http12.message.MediaType; import org.apache.dubbo.rpc.model.FrameworkModel; -@Activate(order = -100, onClass = "com.google.protobuf.Message") +@Activate(order = -100, onClass = CommonConstants.PROTOBUF_MESSAGE_CLASS_NAME) public final class JsonPbCodecFactory implements HttpMessageEncoderFactory, HttpMessageDecoderFactory { @Override diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/PlainTextCodec.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/PlainTextCodec.java index 3ec4a99032d..3f3ec22a75c 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/PlainTextCodec.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/PlainTextCodec.java @@ -17,12 +17,13 @@ package org.apache.dubbo.remoting.http12.message.codec; import org.apache.dubbo.common.io.StreamUtils; -import org.apache.dubbo.common.utils.JsonUtils; +import org.apache.dubbo.remoting.http12.HttpJsonUtils; import org.apache.dubbo.remoting.http12.exception.DecodeException; import org.apache.dubbo.remoting.http12.exception.EncodeException; import org.apache.dubbo.remoting.http12.exception.HttpStatusException; import org.apache.dubbo.remoting.http12.message.HttpMessageCodec; import org.apache.dubbo.remoting.http12.message.MediaType; +import org.apache.dubbo.rpc.model.FrameworkModel; import java.io.InputStream; import java.io.OutputStream; @@ -30,6 +31,18 @@ public final class PlainTextCodec implements HttpMessageCodec { + public static final PlainTextCodec INSTANCE = new PlainTextCodec(); + + private final HttpJsonUtils httpJsonUtils; + + private PlainTextCodec() { + this(FrameworkModel.defaultModel()); + } + + public PlainTextCodec(FrameworkModel frameworkModel) { + httpJsonUtils = frameworkModel.getBeanFactory().getOrRegisterBean(HttpJsonUtils.class); + } + @Override public void encode(OutputStream os, Object data, Charset charset) throws EncodeException { if (data == null) { @@ -40,7 +53,7 @@ public void encode(OutputStream os, Object data, Charset charset) throws EncodeE os.write((data.toString()).getBytes(charset)); return; } - os.write(JsonUtils.toJson(data).getBytes(charset)); + os.write(httpJsonUtils.toJson(data).getBytes(charset)); } catch (HttpStatusException e) { throw e; } catch (Throwable t) { diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/PlainTextCodecFactory.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/PlainTextCodecFactory.java index 69dbc7cfb3f..bed8a7fcd5b 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/PlainTextCodecFactory.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/PlainTextCodecFactory.java @@ -27,11 +27,11 @@ @Activate(order = 10000) public final class PlainTextCodecFactory implements HttpMessageEncoderFactory, HttpMessageDecoderFactory { - private static final PlainTextCodec INSTANCE = new PlainTextCodec(); - @Override public HttpMessageCodec createCodec(URL url, FrameworkModel frameworkModel, String mediaType) { - return INSTANCE; + return frameworkModel == FrameworkModel.defaultModel() + ? PlainTextCodec.INSTANCE + : new PlainTextCodec(frameworkModel); } @Override diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h2/NettyHttp2ProtocolSelectorHandler.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h2/NettyHttp2ProtocolSelectorHandler.java index 9dc05b48d30..c23e176531e 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h2/NettyHttp2ProtocolSelectorHandler.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h2/NettyHttp2ProtocolSelectorHandler.java @@ -21,8 +21,6 @@ import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.common.utils.UrlUtils; import org.apache.dubbo.config.nested.TripleConfig; -import org.apache.dubbo.remoting.http12.HttpHeaderNames; -import org.apache.dubbo.remoting.http12.HttpHeaders; import org.apache.dubbo.remoting.http12.HttpMetadata; import org.apache.dubbo.remoting.http12.command.HttpWriteQueue; import org.apache.dubbo.remoting.http12.exception.UnsupportedMediaTypeException; @@ -64,8 +62,7 @@ public NettyHttp2ProtocolSelectorHandler( @Override protected void channelRead0(ChannelHandlerContext ctx, HttpMetadata metadata) { - HttpHeaders headers = metadata.headers(); - String contentType = headers.getFirst(HttpHeaderNames.CONTENT_TYPE.getName()); + String contentType = metadata.contentType(); Http2ServerTransportListenerFactory factory = UrlUtils.computeServiceAttribute( url, TRANSPORT_LISTENER_FACTORY_CACHE, diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java new file mode 100644 index 00000000000..364684bbd49 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.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.dubbo.remoting.http12.rest; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation for defining OpenAPI on Dubbo service interface. + * + *

Example usage:

+ *
+ * @OpenAPI(tags = {"user=User API"}, title = "User Service", description = "User Service API", version = "1.0.0")
+ * public interface UserService {
+ *     ...
+ * }
+ * 
+ */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface OpenAPI { + + /** + * The openAPI groups. + */ + String group() default ""; + + /** + * The openAPI tags. + *
Supported Syntax
+ *
    + *
  • {@code "name"}
  • + *
  • {@code "name=description"}
  • + *
+ * e.g. user=User API + */ + String[] tags() default {}; + + /** + * The title of the application. + **/ + String infoTitle() default ""; + + /** + * A short description of the application. + **/ + String infoDescription() default ""; + + /** + * The version of the API definition. + **/ + String infoVersion() default ""; + + /** + * A description of the external documentation. + */ + String docDescription() default ""; + + /** + * The URL of the external documentation. + */ + String docUrl() default ""; + + /** + * Indicates whether the mapping is hidden in OpenAPI. + */ + String hidden() default ""; + + /** + * Ordering info. + */ + int order() default 0; + + /** + * The extensions of the OpenAPI. + */ + String[] extensions() default {}; +} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIRequest.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIRequest.java new file mode 100644 index 00000000000..5a3b2d8bd67 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIRequest.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.dubbo.remoting.http12.rest; + +import org.apache.dubbo.common.utils.ToStringUtils; + +import java.io.Serializable; + +/** + * OpenAPI request model. + */ +public class OpenAPIRequest implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * The openAPI group. + */ + private String group; + + /** + * The openAPI version, using a major.minor.patch versioning scheme + * e.g. 1.0.1 + */ + private String version; + + /** + * The openAPI tags. Each tag is an or condition. + */ + private String[] tag; + + /** + * The openAPI services. Each service is an or condition. + */ + private String[] service; + + /** + * The openAPI specification version, using a major.minor.patch versioning scheme + * e.g. 3.0.1, 3.1.0 + *

The default value is '3.0.1'. + */ + @Schema(enumeration = {"3.0.1", "3.1.0"}) + private String openapi; + + /** + * The format of the response. + *

The default value is 'json'. + */ + @Schema(enumeration = {"json", "yaml", "proto"}) + private String format; + + /** + * Whether to pretty print for json. + *

The default value is {@code false}. + */ + private Boolean pretty; + + public String getGroup() { + return group; + } + + public void setGroup(String group) { + this.group = group; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String[] getTag() { + return tag; + } + + public void setTag(String[] tag) { + this.tag = tag; + } + + public String[] getService() { + return service; + } + + public void setService(String[] service) { + this.service = service; + } + + public String getOpenapi() { + return openapi; + } + + public void setOpenapi(String openapi) { + this.openapi = openapi; + } + + public String getFormat() { + return format; + } + + public void setFormat(String format) { + this.format = format; + } + + public Boolean getPretty() { + return pretty; + } + + public void setPretty(Boolean pretty) { + this.pretty = pretty; + } + + @Override + public String toString() { + return ToStringUtils.printToString(this); + } +} diff --git a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/rest/api/ExceptionMapperService.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIService.java similarity index 76% rename from dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/rest/api/ExceptionMapperService.java rename to dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIService.java index 277693d9155..45494e76b3a 100644 --- a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/rest/api/ExceptionMapperService.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIService.java @@ -14,15 +14,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.demo.rest.api; +package org.apache.dubbo.remoting.http12.rest; -import javax.ws.rs.POST; -import javax.ws.rs.Path; +import java.util.Collection; -@Path("/exception/mapper") -public interface ExceptionMapperService { +public interface OpenAPIService { - @POST - @Path("/exception") - String exception(String message); + Collection getOpenAPIGroups(); + + String getDocument(OpenAPIRequest request); + + void refresh(); + + void export(); } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Operation.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Operation.java new file mode 100644 index 00000000000..d1cd645ceb8 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Operation.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.dubbo.remoting.http12.rest; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation for defining an operation in the OpenAPI specification for Dubbo services. + * + *

Example usage:

+ *
+ * @Operation(method = "GET", summary = "Retrieve user", tags = {"user", "retrieve"})
+ * public User getUser(String id) {
+ *     ...
+ * }
+ * 
+ */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Operation { + + /** + * Alias for {@link #summary()}. + */ + String value() default ""; + + /** + * The operation group. + */ + String group() default ""; + + /** + * The operation version. + */ + String version() default ""; + + /** + * The HTTP method for this operation. + */ + String method() default ""; + + /** + * The operation tags. + */ + String[] tags() default {}; + + /** + * The ID of this operation. + **/ + String id() default ""; + + /** + * A brief description of this operation. Should be 120 characters or fewer. + */ + String summary() default ""; + + /** + * A verbose description of the operation. + */ + String description() default ""; + + /** + * Whether this operation is deprecated + */ + boolean deprecated() default false; + + /** + * Indicates whether the operation is hidden in OpenAPI. + */ + String hidden() default ""; + + /** + * The extensions of the OpenAPI. + */ + String[] extensions() default {}; +} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/ParamType.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/ParamType.java index fac5b864c45..4c1fa73533a 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/ParamType.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/ParamType.java @@ -20,6 +20,7 @@ public enum ParamType { PathVariable, MatrixVariable, Param, + Form, Header, Cookie, Attribute, diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Schema.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Schema.java new file mode 100644 index 00000000000..8c5d35c134f --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Schema.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.dubbo.remoting.http12.rest; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation for defining a schema in the OpenAPI specification for Dubbo services. + * + *

Example usage:

+ *
+ * @Schema(title = "User Schema", required = true)
+ * public class User {
+ *     @Schema(title = "User name", example = "Tom")
+ *     private String name;
+ *     ...
+ * }
+ * 
+ */ +@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +public @interface Schema { + + /** + * Alias for {@link #title()}. + */ + String value() default ""; + + /** + * The schema group. + */ + String group() default ""; + + /** + * The schema version. + */ + String version() default ""; + + /** + * The type of the schema. + */ + String type() default ""; + + /** + * The schema's format + */ + String format() default ""; + + /** + * The name of the schema or property. + **/ + String name() default ""; + + /** + * A title to explain the purpose of the schema. + **/ + String title() default ""; + + /** + * The schema's description + **/ + String description() default ""; + + /** + * The maximum value or length of this schema + **/ + String max() default ""; + + /** + * The minimum value or length of this schema + **/ + String min() default ""; + + /** + * The pattern of this schema. + **/ + String pattern() default ""; + + /** + * An example of this schema. + **/ + String example() default ""; + + /** + * A class that implements this schema. + **/ + Class implementation() default Void.class; + + /** + * A list of allowed schema values + **/ + String[] enumeration() default {}; + + /** + * Whether this schema is required + **/ + boolean required() default false; + + /** + * The default value of this schema + **/ + String defaultValue() default ""; + + /** + * Whether this schema is read only + **/ + boolean readOnly() default false; + + /** + * Whether this schema is written only + */ + boolean writeOnly() default false; + + /** + * Whether to flatten the inherited fields from the parent class into the schema. + * If set to {@code true}, the fields from the parent class will be included directly in the schema, + * instead of being treated as a separate schema. + */ + boolean flatten() default false; + + /** + * Whether this schema is nullable + */ + boolean nullable() default false; + + /** + * Whether this operation is deprecated + */ + boolean deprecated() default false; + + /** + * Whether this schema is hidden. + */ + boolean hidden() default false; + + /** + * The extensions of the OpenAPI. + */ + String[] extensions() default {}; +} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory b/dubbo-remoting/dubbo-remoting-http12/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory index 806a3cd1825..bbed05cd1cd 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory @@ -4,3 +4,4 @@ yaml=org.apache.dubbo.remoting.http12.message.codec.YamlCodecFactory xml=org.apache.dubbo.remoting.http12.message.codec.XmlCodecFactory html=org.apache.dubbo.remoting.http12.message.codec.HtmlCodecFactory plaintext=org.apache.dubbo.remoting.http12.message.codec.PlainTextCodecFactory +binary=org.apache.dubbo.remoting.http12.message.codec.BinaryCodecFactory diff --git a/dubbo-remoting/dubbo-remoting-http12/src/test/java/org/apache/dubbo/remoting/http12/message/codec/CodecTest.java b/dubbo-remoting/dubbo-remoting-http12/src/test/java/org/apache/dubbo/remoting/http12/message/codec/CodecTest.java index 9d6d573eef1..43f76abb4a5 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/test/java/org/apache/dubbo/remoting/http12/message/codec/CodecTest.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/test/java/org/apache/dubbo/remoting/http12/message/codec/CodecTest.java @@ -75,7 +75,7 @@ void testPlainText() { Assertions.assertEquals("Hello, world", res); in = new ByteArrayInputStream(utf8Bytes); - codec = new PlainTextCodec(); + codec = PlainTextCodec.INSTANCE; res = (String) codec.decode(in, String.class, Charsets.UTF_8); Assertions.assertEquals("你好,世界", res); diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/java/org/apache/dubbo/demo/provider/GreetingServiceImpl.java b/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/netty4/Constants.java similarity index 75% rename from dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/java/org/apache/dubbo/demo/provider/GreetingServiceImpl.java rename to dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/netty4/Constants.java index cc1b5de4139..1080305dc4e 100644 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/java/org/apache/dubbo/demo/provider/GreetingServiceImpl.java +++ b/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/netty4/Constants.java @@ -14,16 +14,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.demo.provider; +package org.apache.dubbo.remoting.http3.netty4; -import org.apache.dubbo.demo.GreetingService; +public final class Constants { -/** - * - */ -public class GreetingServiceImpl implements GreetingService { - @Override - public String hello() { - return "Greetings!"; - } + public static final String PIPELINE_CONFIGURATOR_KEY = "http3PipelineConfigurator"; + public static final CharSequence TRI_PING = "tri-ping"; + + private Constants() {} } diff --git a/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/netty4/NettyHttp3FrameCodec.java b/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/netty4/NettyHttp3FrameCodec.java index 1737f2dca83..9ef885ed3ec 100644 --- a/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/netty4/NettyHttp3FrameCodec.java +++ b/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/http3/netty4/NettyHttp3FrameCodec.java @@ -17,6 +17,7 @@ package org.apache.dubbo.remoting.http3.netty4; import org.apache.dubbo.common.io.StreamUtils; +import org.apache.dubbo.remoting.http12.HttpStatus; import org.apache.dubbo.remoting.http12.h2.Http2Header; import org.apache.dubbo.remoting.http12.h2.Http2InputMessageFrame; import org.apache.dubbo.remoting.http12.h2.Http2MetadataFrame; @@ -34,7 +35,9 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelOutboundHandler; import io.netty.channel.ChannelPromise; +import io.netty.handler.codec.http2.Http2Headers.PseudoHeaderName; import io.netty.incubator.codec.http3.DefaultHttp3DataFrame; +import io.netty.incubator.codec.http3.DefaultHttp3Headers; import io.netty.incubator.codec.http3.DefaultHttp3HeadersFrame; import io.netty.incubator.codec.http3.Http3DataFrame; import io.netty.incubator.codec.http3.Http3Headers; @@ -42,6 +45,8 @@ import io.netty.incubator.codec.http3.Http3RequestStreamInboundHandler; import io.netty.incubator.codec.quic.QuicStreamChannel; +import static org.apache.dubbo.remoting.http3.netty4.Constants.TRI_PING; + @Sharable public class NettyHttp3FrameCodec extends Http3RequestStreamInboundHandler implements ChannelOutboundHandler { @@ -49,7 +54,21 @@ public class NettyHttp3FrameCodec extends Http3RequestStreamInboundHandler imple @Override protected void channelRead(ChannelHandlerContext ctx, Http3HeadersFrame frame) { - ctx.fireChannelRead(new Http2MetadataFrame(getStreamId(ctx), new DefaultHttpHeaders(frame.headers()), false)); + Http3Headers headers = frame.headers(); + if (headers.contains(TRI_PING)) { + pingReceived(ctx); + return; + } + + ctx.fireChannelRead(new Http2MetadataFrame(getStreamId(ctx), new DefaultHttpHeaders(headers), false)); + } + + private void pingReceived(ChannelHandlerContext ctx) { + Http3Headers pongHeader = new DefaultHttp3Headers(false); + pongHeader.set(TRI_PING, "0"); + pongHeader.set(PseudoHeaderName.STATUS.value(), HttpStatus.OK.getStatusString()); + ctx.write(new DefaultHttp3HeadersFrame(pongHeader)); + ctx.close(); } @Override diff --git a/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/transport/netty4/Helper.java b/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/transport/netty4/Http3Helper.java similarity index 99% rename from dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/transport/netty4/Helper.java rename to dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/transport/netty4/Http3Helper.java index 654831fa14a..4ae742fd56e 100644 --- a/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/transport/netty4/Helper.java +++ b/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/transport/netty4/Http3Helper.java @@ -25,7 +25,7 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS; -final class Helper { +final class Http3Helper { @SuppressWarnings("unchecked") static > T configCodec(QuicCodecBuilder builder, URL url) { diff --git a/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyHttp3ConnectionClient.java b/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyHttp3ConnectionClient.java index fc4388e75d8..a3ad10d8d85 100644 --- a/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyHttp3ConnectionClient.java +++ b/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyHttp3ConnectionClient.java @@ -21,18 +21,19 @@ import org.apache.dubbo.remoting.Constants; import org.apache.dubbo.remoting.RemotingException; import org.apache.dubbo.remoting.http3.Http3SslContexts; -import org.apache.dubbo.remoting.utils.UrlUtils; +import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; +import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPromise; import io.netty.channel.socket.nio.NioDatagramChannel; -import io.netty.handler.timeout.IdleStateHandler; import io.netty.incubator.codec.http3.Http3; import io.netty.incubator.codec.http3.Http3ClientConnectionHandler; import io.netty.incubator.codec.quic.QuicChannel; @@ -40,12 +41,12 @@ import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; -import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.apache.dubbo.remoting.http3.netty4.Constants.PIPELINE_CONFIGURATOR_KEY; public final class NettyHttp3ConnectionClient extends AbstractNettyConnectionClient { + private Consumer pipelineConfigurator; private AtomicReference datagramChannel; - private QuicChannelBootstrap bootstrap; public NettyHttp3ConnectionClient(URL url, ChannelHandler handler) throws RemotingException { @@ -53,16 +54,17 @@ public NettyHttp3ConnectionClient(URL url, ChannelHandler handler) throws Remoti } @Override + @SuppressWarnings("unchecked") protected void initConnectionClient() { super.initConnectionClient(); datagramChannel = new AtomicReference<>(); + pipelineConfigurator = (Consumer) getUrl().getAttribute(PIPELINE_CONFIGURATOR_KEY); + Objects.requireNonNull(pipelineConfigurator, "pipelineConfigurator should be set"); } @Override protected void initBootstrap() throws Exception { - int idleTimeout = UrlUtils.getIdleTimeout(getUrl()); - io.netty.channel.ChannelHandler codec = Helper.configCodec(Http3.newQuicClientCodecBuilder(), getUrl()) - .maxIdleTimeout(idleTimeout, MILLISECONDS) + io.netty.channel.ChannelHandler codec = Http3Helper.configCodec(Http3.newQuicClientCodecBuilder(), getUrl()) .sslContext(Http3SslContexts.buildClientSslContext(getUrl())) .build(); io.netty.channel.Channel nettyDatagramChannel = new Bootstrap() @@ -81,17 +83,15 @@ protected void initChannel(NioDatagramChannel ch) { datagramChannel.set(nettyDatagramChannel); nettyDatagramChannel.closeFuture().addListener(channelFuture -> datagramChannel.set(null)); - int heartbeat = UrlUtils.getHeartbeat(getUrl()); NettyConnectionHandler connectionHandler = new NettyConnectionHandler(this); bootstrap = QuicChannel.newBootstrap(nettyDatagramChannel) .handler(new ChannelInitializer() { @Override protected void initChannel(QuicChannel ch) { - ch.pipeline() - .addLast(new IdleStateHandler(heartbeat, 0, 0, MILLISECONDS)) - .addLast(Constants.CONNECTION_HANDLER_NAME, connectionHandler) - .addLast(new Http3ClientConnectionHandler()); - + ChannelPipeline pipeline = ch.pipeline(); + pipeline.addLast(new Http3ClientConnectionHandler()); + pipeline.addLast(Constants.CONNECTION_HANDLER_NAME, connectionHandler); + pipelineConfigurator.accept(pipeline); ch.closeFuture().addListener(channelFuture -> clearNettyChannel()); } }) diff --git a/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyHttp3Server.java b/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyHttp3Server.java index cd45f5c286a..e9a8634f25f 100644 --- a/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyHttp3Server.java +++ b/dubbo-remoting/dubbo-remoting-http3/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyHttp3Server.java @@ -18,104 +18,78 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.config.ConfigurationUtils; -import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; -import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.remoting.Channel; import org.apache.dubbo.remoting.ChannelHandler; import org.apache.dubbo.remoting.RemotingException; -import org.apache.dubbo.remoting.http12.netty4.HttpWriteQueueHandler; import org.apache.dubbo.remoting.http3.Http3SslContexts; -import org.apache.dubbo.remoting.http3.netty4.NettyHttp3FrameCodec; -import org.apache.dubbo.remoting.http3.netty4.NettyHttp3ProtocolSelectorHandler; import org.apache.dubbo.remoting.transport.AbstractServer; import org.apache.dubbo.remoting.transport.dispatcher.ChannelHandlers; -import org.apache.dubbo.remoting.utils.UrlUtils; -import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ScopeModelUtil; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.Collection; import java.util.Map; +import java.util.Objects; +import java.util.function.Consumer; import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; import io.netty.channel.EventLoopGroup; import io.netty.channel.socket.nio.NioDatagramChannel; -import io.netty.handler.timeout.IdleStateHandler; import io.netty.incubator.codec.http3.Http3; -import io.netty.incubator.codec.http3.Http3ServerConnectionHandler; import io.netty.incubator.codec.quic.InsecureQuicTokenHandler; import io.netty.incubator.codec.quic.QuicChannel; -import io.netty.incubator.codec.quic.QuicStreamChannel; import io.netty.util.concurrent.Future; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_CLOSE; import static org.apache.dubbo.remoting.Constants.EVENT_LOOP_BOSS_POOL_NAME; +import static org.apache.dubbo.remoting.http3.netty4.Constants.PIPELINE_CONFIGURATOR_KEY; public class NettyHttp3Server extends AbstractServer { - private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(NettyHttp3Server.class); - private Map channels; private Bootstrap bootstrap; private EventLoopGroup bossGroup; private io.netty.channel.Channel channel; + private final Consumer pipelineConfigurator; private final int serverShutdownTimeoutMills; + @SuppressWarnings("unchecked") public NettyHttp3Server(URL url, ChannelHandler handler) throws RemotingException { super(url, ChannelHandlers.wrap(handler, url)); + pipelineConfigurator = (Consumer) getUrl().getAttribute(PIPELINE_CONFIGURATOR_KEY); + Objects.requireNonNull(pipelineConfigurator, "pipelineConfigurator should be set"); serverShutdownTimeoutMills = ConfigurationUtils.getServerShutdownTimeout(getUrl().getOrDefaultModuleModel()); } @Override protected void doOpen() throws Throwable { bootstrap = new Bootstrap(); - bossGroup = NettyEventLoopFactory.eventLoopGroup(1, EVENT_LOOP_BOSS_POOL_NAME); - NettyServerHandler nettyServerHandler = new NettyServerHandler(getUrl(), this); channels = nettyServerHandler.getChannels(); - - FrameworkModel frameworkModel = ScopeModelUtil.getFrameworkModel(getUrl().getScopeModel()); - NettyHttp3ProtocolSelectorHandler selectorHandler = - new NettyHttp3ProtocolSelectorHandler(getUrl(), frameworkModel); - - int idleTimeout = UrlUtils.getIdleTimeout(getUrl()); - io.netty.channel.ChannelHandler codec = Helper.configCodec(Http3.newQuicServerCodecBuilder(), getUrl()) - .sslContext(Http3SslContexts.buildServerSslContext(getUrl())) - .maxIdleTimeout(idleTimeout, MILLISECONDS) - .tokenHandler(InsecureQuicTokenHandler.INSTANCE) - .handler(new ChannelInitializer() { - @Override - protected void initChannel(QuicChannel ch) { - ch.pipeline() - .addLast(nettyServerHandler) - .addLast(new IdleStateHandler(0, 0, idleTimeout, MILLISECONDS)) - .addLast(new Http3ServerConnectionHandler(new ChannelInitializer() { - @Override - protected void initChannel(QuicStreamChannel ch) { - ch.pipeline() - .addLast(NettyHttp3FrameCodec.INSTANCE) - .addLast(new HttpWriteQueueHandler()) - .addLast(selectorHandler); - } - })); - } - }) - .build(); - - // bind try { ChannelFuture channelFuture = bootstrap .group(bossGroup) .channel(NioDatagramChannel.class) - .handler(codec) + .handler(Http3Helper.configCodec(Http3.newQuicServerCodecBuilder(), getUrl()) + .sslContext(Http3SslContexts.buildServerSslContext(getUrl())) + .tokenHandler(InsecureQuicTokenHandler.INSTANCE) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(QuicChannel ch) { + ChannelPipeline pipeline = ch.pipeline(); + pipelineConfigurator.accept(pipeline); + pipeline.addLast(nettyServerHandler); + } + }) + .build()) .bind(getBindAddress()); channelFuture.syncUninterruptibly(); channel = channelFuture.channel(); diff --git a/dubbo-remoting/dubbo-remoting-netty/src/main/java/org/apache/dubbo/remoting/transport/netty/NettyClient.java b/dubbo-remoting/dubbo-remoting-netty/src/main/java/org/apache/dubbo/remoting/transport/netty/NettyClient.java index 6ed419f3a35..87cc9dd4459 100644 --- a/dubbo-remoting/dubbo-remoting-netty/src/main/java/org/apache/dubbo/remoting/transport/netty/NettyClient.java +++ b/dubbo-remoting/dubbo-remoting-netty/src/main/java/org/apache/dubbo/remoting/transport/netty/NettyClient.java @@ -18,8 +18,6 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.Version; -import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; -import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.NamedThreadFactory; import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.remoting.ChannelHandler; @@ -48,8 +46,6 @@ */ public class NettyClient extends AbstractClient { - private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(NettyClient.class); - // ChannelFactory's closure has a DirectMemory leak, using static to avoid // https://issues.jboss.org/browse/NETTY-424 private static final ChannelFactory CHANNEL_FACTORY = new NioClientSocketChannelFactory( diff --git a/dubbo-remoting/dubbo-remoting-netty/src/main/java/org/apache/dubbo/remoting/transport/netty/NettyHandler.java b/dubbo-remoting/dubbo-remoting-netty/src/main/java/org/apache/dubbo/remoting/transport/netty/NettyHandler.java index d864639dacc..e9e62b7bb99 100644 --- a/dubbo-remoting/dubbo-remoting-netty/src/main/java/org/apache/dubbo/remoting/transport/netty/NettyHandler.java +++ b/dubbo-remoting/dubbo-remoting-netty/src/main/java/org/apache/dubbo/remoting/transport/netty/NettyHandler.java @@ -78,7 +78,7 @@ public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) thr NettyChannel.removeChannelIfDisconnected(ctx.getChannel()); } - if (logger.isInfoEnabled()) { + if (logger.isInfoEnabled() && channel != null) { logger.info("The connection between " + channel.getRemoteAddress() + " and " + channel.getLocalAddress() + " is established"); } diff --git a/dubbo-remoting/dubbo-remoting-netty/src/main/java/org/apache/dubbo/remoting/transport/netty/NettyPortUnificationServer.java b/dubbo-remoting/dubbo-remoting-netty/src/main/java/org/apache/dubbo/remoting/transport/netty/NettyPortUnificationServer.java index 822b9e1fb1a..dedf9cb8567 100644 --- a/dubbo-remoting/dubbo-remoting-netty/src/main/java/org/apache/dubbo/remoting/transport/netty/NettyPortUnificationServer.java +++ b/dubbo-remoting/dubbo-remoting-netty/src/main/java/org/apache/dubbo/remoting/transport/netty/NettyPortUnificationServer.java @@ -17,8 +17,6 @@ package org.apache.dubbo.remoting.transport.netty; import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; -import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.NamedThreadFactory; import org.apache.dubbo.common.utils.NetUtils; @@ -58,9 +56,6 @@ */ public class NettyPortUnificationServer extends AbstractPortUnificationServer { - private static final ErrorTypeAwareLogger logger = - LoggerFactory.getErrorTypeAwareLogger(NettyPortUnificationServer.class); - private Map dubboChannels = new ConcurrentHashMap<>(); // private ServerBootstrap bootstrap; diff --git a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/AbstractNettyConnectionClient.java b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/AbstractNettyConnectionClient.java index a9f983f56d6..f26ca4d8196 100644 --- a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/AbstractNettyConnectionClient.java +++ b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/AbstractNettyConnectionClient.java @@ -18,8 +18,6 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.Version; -import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; -import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.remoting.Channel; import org.apache.dubbo.remoting.ChannelHandler; @@ -45,9 +43,6 @@ public abstract class AbstractNettyConnectionClient extends AbstractConnectionClient { - private static final ErrorTypeAwareLogger LOGGER = - LoggerFactory.getErrorTypeAwareLogger(AbstractNettyConnectionClient.class); - private AtomicReference> connectingPromiseRef; private AtomicReference channelRef; @@ -94,8 +89,8 @@ protected void initConnectionClient() { protected void doClose() { // AbstractPeer close can set closed true. if (isClosed()) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug(String.format("Connection:%s freed ", this)); + if (logger.isDebugEnabled()) { + logger.debug("Connection:{} freed", this); } performClose(); closePromise.setSuccess(null); @@ -117,9 +112,14 @@ protected void doConnect() throws RemotingException { } if (isClosed()) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug(String.format("%s aborted to reconnect cause connection closed. ", this)); + if (logger.isDebugEnabled()) { + logger.debug("Connection:{} aborted to reconnect cause connection closed", this); } + return; + } + + if (logger.isDebugEnabled()) { + logger.debug("Connection:{} attempting to reconnect to server {}", this, getConnectAddress()); } init.compareAndSet(false, true); @@ -145,11 +145,11 @@ protected void doConnect() throws RemotingException { + ", error message is:" + cause.getMessage(), cause); - LOGGER.error( + logger.error( TRANSPORT_FAILED_CONNECT_PROVIDER, "network disconnected", "", - "Failed to connect to provider server by other reason.", + "Failed to connect to provider server by other reason", cause); throw remotingException; @@ -163,8 +163,8 @@ protected void doConnect() throws RemotingException { + " using dubbo version " + Version.getVersion()); - LOGGER.error( - TRANSPORT_CLIENT_CONNECT_TIMEOUT, "provider crash", "", "Client-side timeout.", remotingException); + logger.error( + TRANSPORT_CLIENT_CONNECT_TIMEOUT, "provider crash", "", "Client-side timeout", remotingException); throw remotingException; } @@ -177,6 +177,17 @@ protected void doDisConnect() { NettyChannel.removeChannelIfDisconnected(getNettyChannel()); } + protected void doReconnect() { + connectivityExecutor.execute(() -> { + try { + doConnect(); + } catch (RemotingException e) { + logger.error( + TRANSPORT_FAILED_RECONNECT, "", "", "Failed to reconnect to server: " + getConnectAddress()); + } + }); + } + @Override public void onConnected(Object channel) { if (!(channel instanceof io.netty.channel.Channel)) { @@ -186,8 +197,8 @@ public void onConnected(Object channel) { io.netty.channel.Channel nettyChannel = ((io.netty.channel.Channel) channel); if (isClosed()) { nettyChannel.close(); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug(String.format("%s is closed, ignoring connected event", this)); + if (logger.isDebugEnabled()) { + logger.debug("Connection:{} is closed, ignoring connected event", this); } return; } @@ -211,8 +222,8 @@ public void onConnected(Object channel) { // Notify the connection is available. connectedPromise.trySuccess(null); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug(String.format("%s connected ", this)); + if (logger.isDebugEnabled()) { + logger.debug("Connection:{} connected", this); } } @@ -229,8 +240,8 @@ public void onGoaway(Object channel) { nettyChannel.close(); } NettyChannel.removeChannelIfDisconnected(nettyChannel); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug(String.format("%s goaway", this)); + if (logger.isDebugEnabled()) { + logger.debug("Connection:{} goaway", this); } } } @@ -272,7 +283,7 @@ public boolean isAvailable() { try { doConnect(); } catch (RemotingException e) { - LOGGER.error(TRANSPORT_FAILED_RECONNECT, "", "", "Failed to connect to server: " + getConnectAddress()); + logger.error(TRANSPORT_FAILED_RECONNECT, "", "", "Failed to connect to server: " + getConnectAddress()); } } @@ -349,36 +360,25 @@ public void operationComplete(ChannelFuture future) { } AbstractNettyConnectionClient connectionClient = AbstractNettyConnectionClient.this; if (connectionClient.isClosed() || connectionClient.getCounter() == 0) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug(String.format( - "%s aborted to reconnect. %s", - connectionClient, future.cause().getMessage())); + if (logger.isDebugEnabled()) { + logger.debug( + "Connection:{} aborted to reconnect. {}", + connectionClient, + future.cause().getMessage()); } return; } - if (LOGGER.isDebugEnabled()) { - LOGGER.debug(String.format( - "%s is reconnecting, attempt=%d cause=%s", - connectionClient, 0, future.cause().getMessage())); + if (logger.isDebugEnabled()) { + logger.debug( + "Connection:{} is reconnecting, attempt=0 cause={}", + connectionClient, + future.cause().getMessage()); } // Notify the connection is unavailable. disconnectedPromise.trySuccess(null); - connectivityExecutor.schedule( - () -> { - try { - connectionClient.doConnect(); - } catch (RemotingException e) { - LOGGER.error( - TRANSPORT_FAILED_RECONNECT, - "", - "", - "Failed to connect to server: " + getConnectAddress()); - } - }, - reconnectDuration, - TimeUnit.MILLISECONDS); + doReconnect(); } } } diff --git a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/AddressUtils.java b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/AddressUtils.java index 85ffb29aa39..6746e339d31 100644 --- a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/AddressUtils.java +++ b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/AddressUtils.java @@ -16,7 +16,6 @@ */ package org.apache.dubbo.remoting.transport.netty4; -import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.rpc.model.FrameworkModel; import java.net.InetSocketAddress; @@ -25,11 +24,17 @@ import io.netty.channel.Channel; +import static org.apache.dubbo.common.utils.NetUtils.toAddressString; + public final class AddressUtils { private static final List ACCESSORS = FrameworkModel.defaultModel().getActivateExtensions(ChannelAddressAccessor.class); + private static final String LOCAL_ADDRESS_KEY = "NETTY_LOCAL_ADDRESS_KEY"; + private static final String REMOTE_ADDRESS_KEY = "NETTY_REMOTE_ADDRESS_KEY"; + private static final String PROTOCOL_KEY = "NETTY_PROTOCOL_KEY"; + private AddressUtils() {} public static InetSocketAddress getRemoteAddress(Channel channel) { @@ -54,35 +59,50 @@ public static InetSocketAddress getLocalAddress(Channel channel) { return (InetSocketAddress) channel.localAddress(); } - public static String getRemoteAddressKey(Channel channel) { - InetSocketAddress address; + static void initAddressIfNecessary(NettyChannel nettyChannel) { + Channel channel = nettyChannel.getNioChannel(); + SocketAddress address = channel.localAddress(); + if (address instanceof InetSocketAddress) { + return; + } + for (int i = 0, size = ACCESSORS.size(); i < size; i++) { ChannelAddressAccessor accessor = ACCESSORS.get(i); - address = accessor.getRemoteAddress(channel); - if (address != null) { - return accessor.getProtocol() + ' ' + NetUtils.toAddressString(address); + InetSocketAddress localAddress = accessor.getLocalAddress(channel); + if (localAddress != null) { + nettyChannel.setAttribute(LOCAL_ADDRESS_KEY, localAddress); + nettyChannel.setAttribute(REMOTE_ADDRESS_KEY, accessor.getRemoteAddress(channel)); + nettyChannel.setAttribute(PROTOCOL_KEY, accessor.getProtocol()); + break; } } - InetSocketAddress remoteAddress = (InetSocketAddress) channel.remoteAddress(); - if (remoteAddress == null) { + } + + static InetSocketAddress getLocalAddress(NettyChannel channel) { + InetSocketAddress address = (InetSocketAddress) channel.getAttribute(LOCAL_ADDRESS_KEY); + return address == null ? (InetSocketAddress) (channel.getNioChannel().localAddress()) : address; + } + + static InetSocketAddress getRemoteAddress(NettyChannel channel) { + InetSocketAddress address = (InetSocketAddress) channel.getAttribute(REMOTE_ADDRESS_KEY); + return address == null ? (InetSocketAddress) (channel.getNioChannel().remoteAddress()) : address; + } + + static String getLocalAddressKey(NettyChannel channel) { + InetSocketAddress address = getLocalAddress(channel); + if (address == null) { return "UNKNOWN"; } - return NetUtils.toAddressString(remoteAddress); + String protocol = (String) channel.getAttribute(PROTOCOL_KEY); + return protocol == null ? toAddressString(address) : protocol + ' ' + toAddressString(address); } - public static String getLocalAddressKey(Channel channel) { - InetSocketAddress address; - for (int i = 0, size = ACCESSORS.size(); i < size; i++) { - ChannelAddressAccessor accessor = ACCESSORS.get(i); - address = accessor.getLocalAddress(channel); - if (address != null) { - return accessor.getProtocol() + ' ' + NetUtils.toAddressString(address); - } - } - SocketAddress localAddress = channel.localAddress(); - if (localAddress == null) { + static String getRemoteAddressKey(NettyChannel channel) { + InetSocketAddress address = getRemoteAddress(channel); + if (address == null) { return "UNKNOWN"; } - return NetUtils.toAddressString((InetSocketAddress) localAddress); + String protocol = (String) channel.getAttribute(PROTOCOL_KEY); + return protocol == null ? toAddressString(address) : protocol + ' ' + toAddressString(address); } } diff --git a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyChannel.java b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyChannel.java index 8191cdfd483..715438a7389 100644 --- a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyChannel.java +++ b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyChannel.java @@ -35,6 +35,7 @@ import java.net.InetSocketAddress; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicBoolean; @@ -73,16 +74,16 @@ final class NettyChannel extends AbstractChannel { private final Netty4BatchWriteQueue writeQueue; - private Codec2 codec; - private final boolean encodeInIOThread; + private Codec2 codec; + /** * The constructor of NettyChannel. * It is private so NettyChannel usually create by {@link NettyChannel#getOrAddChannel(Channel, URL, ChannelHandler)} * * @param channel netty channel - * @param url + * @param url dubbo url * @param handler dubbo handler that contain netty handler */ private NettyChannel(Channel channel, URL url, ChannelHandler handler) { @@ -94,6 +95,7 @@ private NettyChannel(Channel channel, URL url, ChannelHandler handler) { this.writeQueue = Netty4BatchWriteQueue.createWriteQueue(channel); this.codec = getChannelCodec(url); this.encodeInIOThread = getUrl().getParameter(ENCODE_IN_IO_THREAD_KEY, DEFAULT_ENCODE_IN_IO_THREAD); + AddressUtils.initAddressIfNecessary(this); } /** @@ -101,9 +103,8 @@ private NettyChannel(Channel channel, URL url, ChannelHandler handler) { * Put netty channel into it if dubbo channel don't exist in the cache. * * @param ch netty channel - * @param url + * @param url dubbo url * @param handler dubbo handler that contain netty's handler - * @return */ static NettyChannel getOrAddChannel(Channel ch, URL url, ChannelHandler handler) { if (ch == null) { @@ -150,12 +151,20 @@ static void removeChannel(Channel ch) { @Override public InetSocketAddress getLocalAddress() { - return AddressUtils.getLocalAddress(channel); + return AddressUtils.getLocalAddress(this); } @Override public InetSocketAddress getRemoteAddress() { - return AddressUtils.getRemoteAddress(channel); + return AddressUtils.getRemoteAddress(this); + } + + public String getLocalAddressKey() { + return AddressUtils.getLocalAddressKey(this); + } + + public String getRemoteAddressKey() { + return AddressUtils.getRemoteAddressKey(this); } @Override @@ -172,7 +181,7 @@ public void markActive(boolean isActive) { } /** - * Send message by netty and whether to wait the completion of the send. + * Send message by netty and whether to wait the completion of the sending. * * @param message message that need send. * @param sent whether to ack async-sent @@ -193,23 +202,20 @@ public void send(Object message, boolean sent) throws RemotingException { codec.encode(this, buffer, message); outputMessage = buf; } - ChannelFuture future = writeQueue.enqueue(outputMessage).addListener(new ChannelFutureListener() { - @Override - public void operationComplete(ChannelFuture future) throws Exception { - if (!(message instanceof Request)) { + ChannelFuture future = writeQueue.enqueue(outputMessage).addListener((ChannelFutureListener) f -> { + if (!(message instanceof Request)) { + return; + } + ChannelHandler handler = getChannelHandler(); + if (f.isSuccess()) { + handler.sent(NettyChannel.this, message); + } else { + Throwable t = f.cause(); + if (t == null) { return; } - ChannelHandler handler = getChannelHandler(); - if (future.isSuccess()) { - handler.sent(NettyChannel.this, message); - } else { - Throwable t = future.cause(); - if (t == null) { - return; - } - Response response = buildErrorResponse((Request) message, t); - handler.received(NettyChannel.this, response); - } + Response response = buildErrorResponse((Request) message, t); + handler.received(NettyChannel.this, response); } }); @@ -318,18 +324,7 @@ public boolean equals(Object obj) { return channel.equals(client.getNettyChannel()); } - if (getClass() != obj.getClass()) { - return false; - } - NettyChannel other = (NettyChannel) obj; - if (channel == null) { - if (other.channel != null) { - return false; - } - } else if (!channel.equals(other.channel)) { - return false; - } - return true; + return getClass() == obj.getClass() && Objects.equals(channel, ((NettyChannel) obj).channel); } @Override @@ -359,6 +354,7 @@ private static Response buildErrorResponse(Request request, Throwable t) { return response; } + @SuppressWarnings("deprecation") private static Codec2 getChannelCodec(URL url) { String codecName = url.getParameter(Constants.CODEC_KEY); if (StringUtils.isEmpty(codecName)) { diff --git a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyChannelHandler.java b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyChannelHandler.java index 1c31861c5e3..99ce684b150 100644 --- a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyChannelHandler.java +++ b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyChannelHandler.java @@ -56,8 +56,8 @@ public void channelActive(ChannelHandlerContext ctx) throws Exception { logger.info( "The connection {} of {} -> {} is established.", ch, - AddressUtils.getRemoteAddressKey(ch), - AddressUtils.getLocalAddressKey(ch)); + channel.getRemoteAddressKey(), + channel.getLocalAddressKey()); } } } @@ -71,12 +71,13 @@ public void channelInactive(ChannelHandlerContext ctx) throws Exception { dubboChannels.remove(NetUtils.toAddressString((InetSocketAddress) ch.remoteAddress())); if (channel != null) { handler.disconnected(channel); + if (logger.isInfoEnabled()) { logger.info( "The connection {} of {} -> {} is disconnected.", ch, - AddressUtils.getRemoteAddressKey(ch), - AddressUtils.getLocalAddressKey(ch)); + channel.getRemoteAddressKey(), + channel.getLocalAddressKey()); } } } finally { diff --git a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyClient.java b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyClient.java index d01a4810492..bd4d89f5b70 100644 --- a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyClient.java +++ b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyClient.java @@ -20,8 +20,6 @@ import org.apache.dubbo.common.Version; import org.apache.dubbo.common.config.ConfigurationUtils; import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; -import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.resource.GlobalResourceInitializer; import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.common.utils.StringUtils; @@ -67,8 +65,6 @@ public class NettyClient extends AbstractClient { private static final String DEFAULT_SOCKS_PROXY_PORT = "1080"; - private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(NettyClient.class); - /** * netty client bootstrap */ diff --git a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyClientHandler.java b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyClientHandler.java index ed77458cf00..449b39385ae 100644 --- a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyClientHandler.java +++ b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyClientHandler.java @@ -58,12 +58,13 @@ public void channelActive(ChannelHandlerContext ctx) throws Exception { Channel ch = ctx.channel(); NettyChannel channel = NettyChannel.getOrAddChannel(ch, url, handler); handler.connected(channel); + if (logger.isInfoEnabled()) { logger.info( "The connection {} of {} -> {} is established.", ch, - AddressUtils.getLocalAddressKey(ch), - AddressUtils.getRemoteAddressKey(ch)); + channel.getLocalAddressKey(), + channel.getRemoteAddressKey()); } } @@ -81,8 +82,8 @@ public void channelInactive(ChannelHandlerContext ctx) throws Exception { logger.info( "The connection {} of {} -> {} is disconnected.", ch, - AddressUtils.getLocalAddressKey(ch), - AddressUtils.getRemoteAddressKey(ch)); + channel.getLocalAddressKey(), + channel.getRemoteAddressKey()); } } diff --git a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyConnectionHandler.java b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyConnectionHandler.java index 68bffdc9529..9c4d08c0cee 100644 --- a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyConnectionHandler.java +++ b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyConnectionHandler.java @@ -30,7 +30,6 @@ import io.netty.util.Attribute; import io.netty.util.AttributeKey; -import static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_RECONNECT; import static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_UNEXPECTED_EXCEPTION; @Sharable @@ -62,7 +61,7 @@ public void onGoAway(Object channel) { connectionClient.onGoaway(nettyChannel); } if (LOGGER.isDebugEnabled()) { - LOGGER.debug(String.format("Channel %s go away ,schedule reconnect", nettyChannel)); + LOGGER.debug("Channel {} go away ,schedule reconnect", nettyChannel); } reconnect(nettyChannel); } @@ -74,43 +73,30 @@ public void reconnect(Object channel) { } Channel nettyChannel = ((Channel) channel); if (LOGGER.isDebugEnabled()) { - LOGGER.debug(String.format("Connection %s is reconnecting, attempt=%d", connectionClient, 1)); + LOGGER.debug("Connection:{} is reconnecting, attempt={}", connectionClient, 1); } EventLoop eventLoop = nettyChannel.eventLoop(); if (connectionClient.isClosed()) { - LOGGER.info("The client has been closed and will not reconnect. "); + LOGGER.info("The connection {} has been closed and will not reconnect", connectionClient); return; } - eventLoop.schedule( - () -> { - try { - connectionClient.doConnect(); - } catch (Throwable e) { - LOGGER.error( - TRANSPORT_FAILED_RECONNECT, - "", - "", - "Fail to connect to " + connectionClient.getChannel(), - e); - } - }, - 1, - TimeUnit.SECONDS); + eventLoop.schedule(connectionClient::doReconnect, 1, TimeUnit.SECONDS); } @Override public void channelActive(ChannelHandlerContext ctx) { ctx.fireChannelActive(); Channel ch = ctx.channel(); - NettyChannel.getOrAddChannel(ch, connectionClient.getUrl(), connectionClient); + NettyChannel channel = NettyChannel.getOrAddChannel(ch, connectionClient.getUrl(), connectionClient); if (!connectionClient.isClosed()) { connectionClient.onConnected(ch); - if (LOGGER.isInfoEnabled()) { + + if (LOGGER.isInfoEnabled() && channel != null) { LOGGER.info( "The connection {} of {} -> {} is established.", ch, - AddressUtils.getLocalAddressKey(ch), - AddressUtils.getRemoteAddressKey(ch)); + channel.getLocalAddressKey(), + channel.getRemoteAddressKey()); } } else { ctx.close(); @@ -121,16 +107,20 @@ public void channelActive(ChannelHandlerContext ctx) { public void channelInactive(ChannelHandlerContext ctx) throws Exception { super.channelInactive(ctx); Channel ch = ctx.channel(); + NettyChannel channel = NettyChannel.getOrAddChannel(ch, connectionClient.getUrl(), connectionClient); try { Attribute goawayAttr = ch.attr(GO_AWAY_KEY); if (!Boolean.TRUE.equals(goawayAttr.get())) { reconnect(ch); } - LOGGER.info( - "The connection {} of {} -> {} is disconnected.", - ch, - AddressUtils.getLocalAddressKey(ch), - AddressUtils.getRemoteAddressKey(ch)); + + if (LOGGER.isInfoEnabled() && channel != null) { + LOGGER.info( + "The connection {} of {} -> {} is disconnected.", + ch, + channel.getLocalAddressKey(), + channel.getRemoteAddressKey()); + } } finally { NettyChannel.removeChannel(ch); } diff --git a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyPortUnificationServer.java b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyPortUnificationServer.java index 4af9649fc79..5786f3a9db9 100644 --- a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyPortUnificationServer.java +++ b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyPortUnificationServer.java @@ -18,8 +18,6 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.config.ConfigurationUtils; -import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; -import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.remoting.Channel; @@ -59,9 +57,6 @@ */ public class NettyPortUnificationServer extends AbstractPortUnificationServer { - private static final ErrorTypeAwareLogger logger = - LoggerFactory.getErrorTypeAwareLogger(NettyPortUnificationServer.class); - private final int serverShutdownTimeoutMills; /** * netty server bootstrap. diff --git a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServer.java b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServer.java index 6de1969cf19..504931c90f2 100644 --- a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServer.java +++ b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServer.java @@ -18,8 +18,6 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.config.ConfigurationUtils; -import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; -import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.ClassUtils; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.NetUtils; @@ -64,7 +62,6 @@ */ public class NettyServer extends AbstractServer { - private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(NettyServer.class); /** * the cache for alive worker channel. * diff --git a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServerHandler.java b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServerHandler.java index c9987dcdb15..c0eac5df970 100644 --- a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServerHandler.java +++ b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServerHandler.java @@ -75,8 +75,8 @@ public void channelActive(ChannelHandlerContext ctx) throws Exception { logger.info( "The connection {} of {} -> {} is established.", ch, - AddressUtils.getRemoteAddressKey(ch), - AddressUtils.getLocalAddressKey(ch)); + channel.getLocalAddressKey(), + channel.getRemoteAddressKey()); } } @@ -95,8 +95,8 @@ public void channelInactive(ChannelHandlerContext ctx) throws Exception { logger.info( "The connection {} of {} -> {} is disconnected.", ch, - AddressUtils.getRemoteAddressKey(ch), - AddressUtils.getLocalAddressKey(ch)); + channel.getRemoteAddressKey(), + channel.getLocalAddressKey()); } } diff --git a/dubbo-demo/pom.xml b/dubbo-remoting/dubbo-remoting-websocket/pom.xml similarity index 69% rename from dubbo-demo/pom.xml rename to dubbo-remoting/dubbo-remoting-websocket/pom.xml index 30b2a1e5dc8..b27869d056a 100644 --- a/dubbo-demo/pom.xml +++ b/dubbo-remoting/dubbo-remoting-websocket/pom.xml @@ -19,27 +19,23 @@ 4.0.0 org.apache.dubbo - dubbo-parent + dubbo-remoting ${revision} ../pom.xml - dubbo-demo - pom + dubbo-remoting-websocket + jar ${project.artifactId} - The demo module of dubbo project - - - dubbo-demo-interface - dubbo-demo-xml - dubbo-demo-annotation - dubbo-demo-api - dubbo-demo-generic-call - dubbo-demo-triple - dubbo-demo-native - dubbo-demo-spring-boot - - + The websocket remoting module of dubbo project - true + false + + + + org.apache.dubbo + dubbo-remoting-http12 + ${project.parent.version} + + diff --git a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-interface/src/main/java/org/apache/dubbo/graalvm/demo/DemoService.java b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/FinalFragment.java similarity index 88% rename from dubbo-demo/dubbo-demo-native/dubbo-demo-native-interface/src/main/java/org/apache/dubbo/graalvm/demo/DemoService.java rename to dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/FinalFragment.java index 8e338c4bacb..c3028962df7 100644 --- a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-interface/src/main/java/org/apache/dubbo/graalvm/demo/DemoService.java +++ b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/FinalFragment.java @@ -14,9 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.graalvm.demo; +package org.apache.dubbo.remoting.websocket; -public interface DemoService { +public interface FinalFragment { - String sayHello(String name); + boolean isFinalFragment(); } diff --git a/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/FinalFragmentByteArrayInputStream.java b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/FinalFragmentByteArrayInputStream.java new file mode 100644 index 00000000000..0176e352656 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/FinalFragmentByteArrayInputStream.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.dubbo.remoting.websocket; + +import java.io.ByteArrayInputStream; + +public class FinalFragmentByteArrayInputStream extends ByteArrayInputStream implements FinalFragment { + + private final boolean finalFragment; + + public FinalFragmentByteArrayInputStream(byte[] buf) { + this(buf, 0, buf.length); + } + + public FinalFragmentByteArrayInputStream(byte[] buf, boolean finalFragment) { + this(buf, 0, buf.length, finalFragment); + } + + public FinalFragmentByteArrayInputStream(byte[] buf, int offset, int length) { + this(buf, offset, length, false); + } + + public FinalFragmentByteArrayInputStream(byte[] buf, int offset, int length, boolean finalFragment) { + super(buf, offset, length); + this.finalFragment = finalFragment; + } + + @Override + public boolean isFinalFragment() { + return finalFragment; + } +} diff --git a/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/FinalFragmentByteBufInputStream.java b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/FinalFragmentByteBufInputStream.java new file mode 100644 index 00000000000..5bd5e1fe944 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/FinalFragmentByteBufInputStream.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.dubbo.remoting.websocket; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufInputStream; + +public class FinalFragmentByteBufInputStream extends ByteBufInputStream implements FinalFragment { + + private final boolean finalFragment; + + public FinalFragmentByteBufInputStream(ByteBuf buffer) { + this(buffer, buffer.readableBytes()); + } + + public FinalFragmentByteBufInputStream(ByteBuf buffer, int length) { + this(buffer, length, false); + } + + public FinalFragmentByteBufInputStream(ByteBuf buffer, boolean releaseOnClose) { + this(buffer, buffer.readableBytes(), releaseOnClose); + } + + public FinalFragmentByteBufInputStream(ByteBuf buffer, boolean releaseOnClose, boolean finalFragment) { + this(buffer, buffer.readableBytes(), releaseOnClose, finalFragment); + } + + public FinalFragmentByteBufInputStream(ByteBuf buffer, int length, boolean releaseOnClose) { + this(buffer, length, releaseOnClose, false); + } + + public FinalFragmentByteBufInputStream(ByteBuf buffer, int length, boolean releaseOnClose, boolean finalFragment) { + super(buffer, length, releaseOnClose); + this.finalFragment = finalFragment; + } + + @Override + public boolean isFinalFragment() { + return finalFragment; + } +} diff --git a/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/FinalFragmentStreamingDecoder.java b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/FinalFragmentStreamingDecoder.java new file mode 100644 index 00000000000..d5530171186 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/FinalFragmentStreamingDecoder.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.dubbo.remoting.websocket; + +import org.apache.dubbo.remoting.http12.CompositeInputStream; +import org.apache.dubbo.remoting.http12.exception.DecodeException; +import org.apache.dubbo.remoting.http12.message.StreamingDecoder; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +public class FinalFragmentStreamingDecoder implements StreamingDecoder { + + private boolean inDelivery; + + private boolean pendingDelivery; + + private boolean closed; + + private boolean closing; + + protected final CompositeInputStream accumulate = new CompositeInputStream(); + + protected FragmentListener listener; + + @Override + public void request(int numMessages) {} + + @Override + public void decode(InputStream inputStream) throws DecodeException { + if (closing || closed) { + // ignored + return; + } + accumulate.addInputStream(inputStream); + if (inputStream instanceof FinalFragment && ((FinalFragment) inputStream).isFinalFragment()) { + pendingDelivery = true; + deliver(); + } + } + + @Override + public void close() { + closing = true; + deliver(); + } + + @Override + public void onStreamClosed() { + if (closed) { + return; + } + closed = true; + try { + accumulate.close(); + } catch (IOException e) { + throw new DecodeException(e); + } + } + + @Override + public void setFragmentListener(FragmentListener listener) { + this.listener = listener; + } + + private void deliver() { + if (inDelivery) { + return; + } + if (closed) { + return; + } + inDelivery = true; + try { + if (pendingDelivery) { + processBody(); + pendingDelivery = false; + } + if (closing) { + if (!closed) { + closed = true; + accumulate.close(); + listener.onClose(); + } + } + } catch (IOException e) { + throw new DecodeException(e); + } finally { + inDelivery = false; + } + } + + private void processBody() throws IOException { + byte[] rawMessage = readRawMessage(accumulate, accumulate.available()); + InputStream inputStream = new ByteArrayInputStream(rawMessage); + invokeListener(inputStream); + } + + protected void invokeListener(InputStream inputStream) { + this.listener.onFragmentMessage(inputStream); + } + + protected byte[] readRawMessage(InputStream inputStream, int length) throws IOException { + byte[] data = new byte[length]; + inputStream.read(data, 0, length); + return data; + } +} diff --git a/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/WebSocketHeaderNames.java b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/WebSocketHeaderNames.java new file mode 100644 index 00000000000..b5a1d87f9a0 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/WebSocketHeaderNames.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.dubbo.remoting.websocket; + +public enum WebSocketHeaderNames { + WEBSOCKET_MESSAGE("websocket-message"); + + private final String name; + + WebSocketHeaderNames(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/WebSocketServerTransportListenerFactory.java b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/WebSocketServerTransportListenerFactory.java new file mode 100644 index 00000000000..94ea29f9a3c --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/WebSocketServerTransportListenerFactory.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.dubbo.remoting.websocket; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.extension.ExtensionScope; +import org.apache.dubbo.common.extension.SPI; +import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; +import org.apache.dubbo.rpc.model.FrameworkModel; + +@SPI(scope = ExtensionScope.FRAMEWORK) +public interface WebSocketServerTransportListenerFactory { + + WebSocketTransportListener newInstance(H2StreamChannel streamChannel, URL url, FrameworkModel frameworkModel); +} diff --git a/dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/GreeterWrapperService.java b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/WebSocketTransportListener.java similarity index 80% rename from dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/GreeterWrapperService.java rename to dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/WebSocketTransportListener.java index bb90d4c54f3..09fb6ba47cf 100644 --- a/dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/GreeterWrapperService.java +++ b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/WebSocketTransportListener.java @@ -14,12 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.demo; +package org.apache.dubbo.remoting.websocket; -public interface GreeterWrapperService { +import org.apache.dubbo.remoting.http12.h2.Http2TransportListener; - /** - * Sends a greeting - */ - String sayHello(String request); -} +public interface WebSocketTransportListener extends Http2TransportListener {} diff --git a/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/NettyWebSocketChannel.java b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/NettyWebSocketChannel.java new file mode 100644 index 00000000000..261687562c8 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/NettyWebSocketChannel.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.dubbo.remoting.websocket.netty4; + +import org.apache.dubbo.config.nested.TripleConfig; +import org.apache.dubbo.remoting.http12.HttpMetadata; +import org.apache.dubbo.remoting.http12.HttpOutputMessage; +import org.apache.dubbo.remoting.http12.LimitedByteBufOutputStream; +import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; +import org.apache.dubbo.remoting.http12.h2.Http2OutputMessage; +import org.apache.dubbo.remoting.http12.h2.Http2OutputMessageFrame; +import org.apache.dubbo.remoting.http12.netty4.NettyHttpChannelFutureListener; + +import java.net.SocketAddress; +import java.util.concurrent.CompletableFuture; + +import io.netty.channel.Channel; + +public class NettyWebSocketChannel implements H2StreamChannel { + + private final Channel channel; + + private final TripleConfig tripleConfig; + + public NettyWebSocketChannel(Channel channel, TripleConfig tripleConfig) { + this.channel = channel; + this.tripleConfig = tripleConfig; + } + + @Override + public CompletableFuture writeResetFrame(long errorCode) { + NettyHttpChannelFutureListener futureListener = new NettyHttpChannelFutureListener(); + channel.close().addListener(futureListener); + return futureListener; + } + + @Override + public Http2OutputMessage newOutputMessage(boolean endStream) { + return new Http2OutputMessageFrame( + new LimitedByteBufOutputStream( + channel.alloc().buffer(), tripleConfig.getMaxResponseBodySizeOrDefault()), + endStream); + } + + @Override + public CompletableFuture writeHeader(HttpMetadata httpMetadata) { + NettyHttpChannelFutureListener futureListener = new NettyHttpChannelFutureListener(); + channel.write(httpMetadata).addListener(futureListener); + return futureListener; + } + + @Override + public CompletableFuture writeMessage(HttpOutputMessage httpOutputMessage) { + NettyHttpChannelFutureListener futureListener = new NettyHttpChannelFutureListener(); + channel.write(httpOutputMessage).addListener(futureListener); + return futureListener; + } + + @Override + public SocketAddress remoteAddress() { + return channel.remoteAddress(); + } + + @Override + public SocketAddress localAddress() { + return channel.localAddress(); + } + + @Override + public void flush() { + channel.flush(); + } +} diff --git a/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/WebSocketFrameCodec.java b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/WebSocketFrameCodec.java new file mode 100644 index 00000000000..0bf25d1dac4 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/WebSocketFrameCodec.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.dubbo.remoting.websocket.netty4; + +import org.apache.dubbo.common.io.StreamUtils; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.remoting.http12.HttpHeaderNames; +import org.apache.dubbo.remoting.http12.HttpHeaders; +import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.remoting.http12.HttpStatus; +import org.apache.dubbo.remoting.http12.h2.Http2Header; +import org.apache.dubbo.remoting.http12.h2.Http2InputMessage; +import org.apache.dubbo.remoting.http12.h2.Http2InputMessageFrame; +import org.apache.dubbo.remoting.http12.h2.Http2MetadataFrame; +import org.apache.dubbo.remoting.http12.h2.Http2OutputMessage; +import org.apache.dubbo.remoting.http12.netty4.h1.NettyHttp1HttpHeaders; +import org.apache.dubbo.remoting.websocket.FinalFragmentByteBufInputStream; +import org.apache.dubbo.remoting.websocket.WebSocketHeaderNames; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufOutputStream; +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPromise; +import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; +import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketCloseStatus; +import io.netty.handler.codec.http.websocketx.WebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; +import io.netty.handler.codec.http2.DefaultHttp2ResetFrame; + +public class WebSocketFrameCodec extends ChannelDuplexHandler { + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + if (msg instanceof BinaryWebSocketFrame || msg instanceof TextWebSocketFrame) { + Http2InputMessage http2InputMessage = onDataFrame((WebSocketFrame) msg); + super.channelRead(ctx, http2InputMessage); + } else if (msg instanceof CloseWebSocketFrame) { + Object closeMessage = onCloseFrame((CloseWebSocketFrame) msg); + super.channelRead(ctx, closeMessage); + } else { + super.channelRead(ctx, msg); + } + } + + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + if (msg instanceof Http2OutputMessage) { + WebSocketFrame webSocketFrame = encodeWebSocketFrame(ctx, (Http2OutputMessage) msg); + super.write(ctx, webSocketFrame, promise); + } else if (msg instanceof Http2Header) { + Http2Header http2Header = (Http2Header) msg; + if (http2Header.isEndStream()) { + CloseWebSocketFrame closeWebSocketFrame = encodeCloseWebSocketFrame(http2Header); + super.write(ctx, closeWebSocketFrame, promise); + } + } else { + super.write(ctx, msg, promise); + } + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) { + Http2Header http2Header = onHandshakeComplete((WebSocketServerProtocolHandler.HandshakeComplete) evt); + super.channelRead(ctx, http2Header); + } else { + super.userEventTriggered(ctx, evt); + } + } + + private Http2Header onHandshakeComplete(WebSocketServerProtocolHandler.HandshakeComplete evt) { + HttpHeaders httpHeaders = new NettyHttp1HttpHeaders(evt.requestHeaders()); + httpHeaders.set(HttpHeaderNames.PATH.getName(), evt.requestUri()); + httpHeaders.set(HttpHeaderNames.METHOD.getName(), HttpMethods.POST.name()); + return new Http2MetadataFrame(httpHeaders); + } + + private Http2InputMessageFrame onDataFrame(WebSocketFrame webSocketFrame) { + ByteBuf data = webSocketFrame.content(); + return new Http2InputMessageFrame( + new FinalFragmentByteBufInputStream(data, true, webSocketFrame.isFinalFragment()), false); + } + + private Object onCloseFrame(CloseWebSocketFrame closeWebSocketFrame) { + if (closeWebSocketFrame.statusCode() != WebSocketCloseStatus.NORMAL_CLOSURE.code()) { + return new DefaultHttp2ResetFrame(closeWebSocketFrame.statusCode()); + } + return new Http2InputMessageFrame(StreamUtils.EMPTY, true); + } + + private CloseWebSocketFrame encodeCloseWebSocketFrame(Http2Header http2Header) { + HttpHeaders headers = http2Header.headers(); + List statusHeaders = headers.remove(HttpHeaderNames.STATUS.getName()); + WebSocketCloseStatus status = WebSocketCloseStatus.NORMAL_CLOSURE; + if (CollectionUtils.isNotEmpty(statusHeaders) + && !HttpStatus.OK.getStatusString().equals(statusHeaders.get(0))) { + List messageHeaders = headers.remove(WebSocketHeaderNames.WEBSOCKET_MESSAGE.getName()); + status = new WebSocketCloseStatus( + WebSocketCloseStatus.INTERNAL_SERVER_ERROR.code(), + CollectionUtils.isNotEmpty(messageHeaders) + ? messageHeaders.get(0) + : WebSocketCloseStatus.INTERNAL_SERVER_ERROR.reasonText()); + } + return new CloseWebSocketFrame(status); + } + + private WebSocketFrame encodeWebSocketFrame(ChannelHandlerContext ctx, Http2OutputMessage outputMessage) + throws IOException { + OutputStream body = outputMessage.getBody(); + if (body == null) { + return new BinaryWebSocketFrame(); + } + if (body instanceof ByteBufOutputStream) { + ByteBuf buffer = ((ByteBufOutputStream) body).buffer(); + return new BinaryWebSocketFrame(buffer); + } + throw new IllegalArgumentException("Http2OutputMessage body must be ByteBufOutputStream"); + } +} diff --git a/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/WebSocketProtocolSelectorHandler.java b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/WebSocketProtocolSelectorHandler.java new file mode 100644 index 00000000000..1ac8bfbdb98 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/WebSocketProtocolSelectorHandler.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.dubbo.remoting.websocket.netty4; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.config.nested.TripleConfig; +import org.apache.dubbo.remoting.http12.command.HttpWriteQueue; +import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; +import org.apache.dubbo.remoting.http12.h2.command.Http2WriteQueueChannel; +import org.apache.dubbo.remoting.http12.netty4.HttpWriteQueueHandler; +import org.apache.dubbo.remoting.http12.netty4.h2.NettyHttp2FrameHandler; +import org.apache.dubbo.remoting.websocket.WebSocketServerTransportListenerFactory; +import org.apache.dubbo.remoting.websocket.WebSocketTransportListener; +import org.apache.dubbo.rpc.model.FrameworkModel; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.FullHttpRequest; + +public class WebSocketProtocolSelectorHandler extends SimpleChannelInboundHandler { + + private final URL url; + + private final FrameworkModel frameworkModel; + + private final TripleConfig tripleConfig; + + private final WebSocketServerTransportListenerFactory defaultWebSocketServerTransportListenerFactory; + + public WebSocketProtocolSelectorHandler( + URL url, + FrameworkModel frameworkModel, + TripleConfig tripleConfig, + WebSocketServerTransportListenerFactory defaultWebSocketServerTransportListenerFactory) { + this.url = url; + this.frameworkModel = frameworkModel; + this.tripleConfig = tripleConfig; + this.defaultWebSocketServerTransportListenerFactory = defaultWebSocketServerTransportListenerFactory; + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) { + H2StreamChannel streamChannel = new NettyWebSocketChannel(ctx.channel(), tripleConfig); + HttpWriteQueueHandler writeQueueHandler = ctx.channel().pipeline().get(HttpWriteQueueHandler.class); + if (writeQueueHandler != null) { + HttpWriteQueue writeQueue = writeQueueHandler.getWriteQueue(); + streamChannel = new Http2WriteQueueChannel(streamChannel, writeQueue); + } + WebSocketTransportListener webSocketTransportListener = + defaultWebSocketServerTransportListenerFactory.newInstance(streamChannel, url, frameworkModel); + ctx.channel().closeFuture().addListener(future -> webSocketTransportListener.close()); + ctx.pipeline() + .addLast(new NettyHttp2FrameHandler(streamChannel, webSocketTransportListener)) + .remove(this); + ctx.fireChannelRead(msg.retain()); + } +} diff --git a/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/WebSocketServerUpgradeCodec.java b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/WebSocketServerUpgradeCodec.java new file mode 100644 index 00000000000..1970d2162a3 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-websocket/src/main/java/org/apache/dubbo/remoting/websocket/netty4/WebSocketServerUpgradeCodec.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.dubbo.remoting.websocket.netty4; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpServerUpgradeHandler; + +public class WebSocketServerUpgradeCodec implements HttpServerUpgradeHandler.UpgradeCodec { + + private final List> shouldRemoveChannelHandlers; + + private final ChannelHandler[] channelHandlers; + + public WebSocketServerUpgradeCodec( + List> shouldRemoveChannelHandlers, ChannelHandler... channelHandlers) { + this.shouldRemoveChannelHandlers = shouldRemoveChannelHandlers; + this.channelHandlers = channelHandlers; + } + + @Override + public Collection requiredUpgradeHeaders() { + return Collections.emptyList(); + } + + @Override + public boolean prepareUpgradeResponse( + ChannelHandlerContext ctx, FullHttpRequest upgradeRequest, HttpHeaders upgradeHeaders) { + if (shouldRemoveChannelHandlers != null) { + for (Class shouldRemoveChannelHandler : shouldRemoveChannelHandlers) { + ctx.pipeline().remove(shouldRemoveChannelHandler); + } + } + if (channelHandlers != null) { + for (ChannelHandler channelHandler : channelHandlers) { + ctx.pipeline().addLast(channelHandler); + } + } + return false; + } + + @Override + public void upgradeTo(ChannelHandlerContext ctx, FullHttpRequest upgradeRequest) {} +} diff --git a/dubbo-remoting/dubbo-remoting-zookeeper-curator5/pom.xml b/dubbo-remoting/dubbo-remoting-zookeeper-curator5/pom.xml index 5b8510d6f88..54de827c327 100644 --- a/dubbo-remoting/dubbo-remoting-zookeeper-curator5/pom.xml +++ b/dubbo-remoting/dubbo-remoting-zookeeper-curator5/pom.xml @@ -30,7 +30,7 @@ false 3.7.2 - 5.1.0 + 5.7.1 diff --git a/dubbo-remoting/pom.xml b/dubbo-remoting/pom.xml index 2384d0c81ad..2546529bda7 100644 --- a/dubbo-remoting/pom.xml +++ b/dubbo-remoting/pom.xml @@ -34,6 +34,7 @@ dubbo-remoting-netty4 dubbo-remoting-http12 dubbo-remoting-http3 + dubbo-remoting-websocket false diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AdaptiveScopeModelInitializer.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AdaptiveScopeModelInitializer.java index 2d7c0f3c1c9..24860c7cb7c 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AdaptiveScopeModelInitializer.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AdaptiveScopeModelInitializer.java @@ -18,20 +18,13 @@ import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; import org.apache.dubbo.rpc.model.ApplicationModel; -import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; public class AdaptiveScopeModelInitializer implements ScopeModelInitializer { - @Override - public void initializeFrameworkModel(FrameworkModel frameworkModel) {} @Override public void initializeApplicationModel(ApplicationModel applicationModel) { ScopeBeanFactory beanFactory = applicationModel.getBeanFactory(); beanFactory.registerBean(AdaptiveMetrics.class); } - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Constants.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Constants.java index c5b4bdb18a8..bf64a3578f4 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Constants.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Constants.java @@ -109,12 +109,15 @@ public interface Constants { String H2_SETTINGS_BUILTIN_SERVICE_INIT = "dubbo.tri.builtin.service.init"; String H2_SETTINGS_JSON_FRAMEWORK_NAME = "dubbo.protocol.triple.rest.json-framework"; + String H2_SETTINGS_DISALLOWED_CONTENT_TYPES = "dubbo.protocol.triple.rest.disallowed-content-types"; + String H2_SETTINGS_OPENAPI_PREFIX = "dubbo.protocol.triple.rest.openapi"; String H2_SETTINGS_VERBOSE_ENABLED = "dubbo.protocol.triple.verbose"; + String H2_SETTINGS_REST_ENABLED = "dubbo.protocol.triple.rest.enabled"; + String H2_SETTINGS_OPENAPI_ENABLED = "dubbo.protocol.triple.rest.openapi.enabled"; String H2_SETTINGS_SERVLET_ENABLED = "dubbo.protocol.triple.servlet.enabled"; String H3_SETTINGS_HTTP3_ENABLED = "dubbo.protocol.triple.http3.enabled"; String H3_SETTINGS_HTTP3_NEGOTIATION = "dubbo.protocol.triple.http3.negotiation"; - String H2_SETTINGS_CONNECTION_INITIAL_WINDOW_SIZE_KEY = "dubbo.rpc.tri.connection-initial-window-size"; String ADAPTIVE_LOADBALANCE_ATTACHMENT_KEY = "lb_adaptive"; String ADAPTIVE_LOADBALANCE_START_TIME = "adaptive_startTime"; diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcInvocation.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcInvocation.java index 4c69c499338..1aec29ef1ef 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcInvocation.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcInvocation.java @@ -501,6 +501,10 @@ public void setInvoker(Invoker invoker) { this.invoker = invoker; } + public Object remove(Object key) { + return attributes.remove(key); + } + @Override public Object put(Object key, Object value) { return attributes.put(key, value); diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcScopeModelInitializer.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcScopeModelInitializer.java index cfde6bc9cc1..e863a654d1a 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcScopeModelInitializer.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcScopeModelInitializer.java @@ -18,23 +18,16 @@ import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; import org.apache.dubbo.rpc.listener.InjvmExporterListener; -import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; import org.apache.dubbo.rpc.protocol.PermittedSerializationKeeper; public class RpcScopeModelInitializer implements ScopeModelInitializer { + @Override public void initializeFrameworkModel(FrameworkModel frameworkModel) { ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory(); beanFactory.registerBean(InjvmExporterListener.class); beanFactory.registerBean(PermittedSerializationKeeper.class); } - - @Override - public void initializeApplicationModel(ApplicationModel applicationModel) {} - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/rest/api/CurlService.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/stub/annotations/GRequest.java similarity index 67% rename from dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/rest/api/CurlService.java rename to dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/stub/annotations/GRequest.java index b77cded2f57..4e6144f908f 100644 --- a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/rest/api/CurlService.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/stub/annotations/GRequest.java @@ -14,17 +14,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.demo.rest.api; +package org.apache.dubbo.rpc.stub.annotations; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.Path; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; -@Path("/curl") -public interface CurlService { - // curl -X GET http://localhost:8888/services/curl - // http://localhost:8888/services/curl - @GET - @Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN}) - String curl(); +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface GRequest { + String value() default ""; } diff --git a/dubbo-rpc/dubbo-rpc-triple/pom.xml b/dubbo-rpc/dubbo-rpc-triple/pom.xml index 2e7085832f9..1b4bebf035c 100644 --- a/dubbo-rpc/dubbo-rpc-triple/pom.xml +++ b/dubbo-rpc/dubbo-rpc-triple/pom.xml @@ -49,29 +49,48 @@ org.apache.dubbo - dubbo-remoting-netty4 + dubbo-remoting-websocket ${project.parent.version} true org.apache.dubbo - dubbo-cluster + dubbo-remoting-netty4 ${project.parent.version} - test + true - io.netty - netty-codec-http2 + org.apache.dubbo + dubbo-native + ${project.parent.version} com.google.protobuf - protobuf-java + protobuf-java-util + true + + org.apache.commons + commons-compress + true + + + org.xerial.snappy + snappy-java + true + + org.springframework spring-test test + + org.apache.dubbo + dubbo-cluster + ${project.parent.version} + test + org.apache.dubbo dubbo-serialization-hessian2 @@ -89,19 +108,11 @@ log4j-slf4j-impl test - - org.apache.commons - commons-compress - io.reactivex.rxjava2 rxjava test - - org.xerial.snappy - snappy-java - io.projectreactor reactor-core @@ -112,18 +123,6 @@ spock-core test - - org.apache.dubbo - dubbo-native - ${project.parent.version} - - - - org.apache.dubbo - dubbo-compiler - ${project.parent.version} - provided - @@ -143,14 +142,6 @@ org.apache.dubbo dubbo-maven-plugin - ${project.version} - - - - compile - - - diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ExceptionUtils.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ExceptionUtils.java index 17417b51372..39edd43fe6a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ExceptionUtils.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ExceptionUtils.java @@ -16,7 +16,10 @@ */ package org.apache.dubbo.rpc.protocol.tri; +import org.apache.dubbo.common.logger.Level; import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.remoting.http12.HttpStatus; +import org.apache.dubbo.remoting.http12.exception.HttpStatusException; import java.io.PrintWriter; import java.io.StringWriter; @@ -30,8 +33,6 @@ public class ExceptionUtils { - private static final int NOT_FOUND = -1; - public static String getStackTrace(final Throwable throwable) { final StringWriter sw = new StringWriter(); final PrintWriter pw = new PrintWriter(sw, true); @@ -82,6 +83,19 @@ public static List getStackFrameList(final Throwable t) { return getStackFrameList(t, Integer.MAX_VALUE); } + public static Level resolveLogLevel(final Throwable t) { + if (t instanceof HttpStatusException) { + int httpStatusCode = ((HttpStatusException) t).getStatusCode(); + if (httpStatusCode < HttpStatus.BAD_REQUEST.getCode()) { + return TripleProtocol.VERBOSE_ENABLED ? Level.INFO : Level.DEBUG; + } + if (httpStatusCode < HttpStatus.INTERNAL_SERVER_ERROR.getCode()) { + return Level.INFO; + } + } + return Level.ERROR; + } + /** * Wrap as runtime exception */ diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/Http3Exchanger.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/Http3Exchanger.java index 247fe70dc82..3394a81295a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/Http3Exchanger.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/Http3Exchanger.java @@ -19,25 +19,42 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.config.Configuration; import org.apache.dubbo.common.constants.LoggerCodeConstants; -import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; -import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.logger.FluentLogger; import org.apache.dubbo.common.utils.ClassUtils; import org.apache.dubbo.remoting.ChannelHandler; import org.apache.dubbo.remoting.RemotingException; import org.apache.dubbo.remoting.RemotingServer; import org.apache.dubbo.remoting.api.connection.AbstractConnectionClient; +import org.apache.dubbo.remoting.http12.netty4.HttpWriteQueueHandler; +import org.apache.dubbo.remoting.http3.netty4.NettyHttp3FrameCodec; +import org.apache.dubbo.remoting.http3.netty4.NettyHttp3ProtocolSelectorHandler; import org.apache.dubbo.remoting.transport.ChannelHandlerAdapter; import org.apache.dubbo.remoting.transport.netty4.NettyHttp3Server; +import org.apache.dubbo.remoting.utils.UrlUtils; import org.apache.dubbo.rpc.Constants; +import org.apache.dubbo.rpc.model.ScopeModelUtil; +import org.apache.dubbo.rpc.protocol.tri.h3.Http3ClientFrameCodec; +import org.apache.dubbo.rpc.protocol.tri.h3.Http3TripleServerConnectionHandler; import org.apache.dubbo.rpc.protocol.tri.h3.negotiation.Helper; import java.util.ArrayList; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.handler.flush.FlushConsolidationHandler; +import io.netty.handler.timeout.IdleStateHandler; +import io.netty.incubator.codec.http3.Http3ServerConnectionHandler; +import io.netty.incubator.codec.quic.QuicStreamChannel; + +import static org.apache.dubbo.remoting.http3.netty4.Constants.PIPELINE_CONFIGURATOR_KEY; public final class Http3Exchanger { - private static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(Http3Exchanger.class); + private static final FluentLogger LOGGER = FluentLogger.of(Http3Exchanger.class); private static final boolean HAS_NETTY_HTTP3 = ClassUtils.isPresent("io.netty.incubator.codec.http3.Http3"); private static final Map SERVERS = new ConcurrentHashMap<>(); private static final Map CLIENTS = new ConcurrentHashMap<>(16); @@ -65,7 +82,8 @@ public static RemotingServer bind(URL url) { if (isEnabled(url)) { return SERVERS.computeIfAbsent(url.getAddress(), addr -> { try { - return new NettyHttp3Server(url, HANDLER); + URL serverUrl = url.putAttribute(PIPELINE_CONFIGURATOR_KEY, configServerPipeline(url)); + return new NettyHttp3Server(serverUrl, HANDLER); } catch (RemotingException e) { throw new RuntimeException(e); } @@ -74,12 +92,31 @@ public static RemotingServer bind(URL url) { return null; } + private static Consumer configServerPipeline(URL url) { + NettyHttp3ProtocolSelectorHandler selectorHandler = + new NettyHttp3ProtocolSelectorHandler(url, ScopeModelUtil.getFrameworkModel(url.getScopeModel())); + return pipeline -> { + pipeline.addLast(new Http3ServerConnectionHandler(new ChannelInitializer() { + @Override + protected void initChannel(QuicStreamChannel ch) { + ch.pipeline() + .addLast(new HttpWriteQueueHandler()) + .addLast(new FlushConsolidationHandler(64, true)) + .addLast(NettyHttp3FrameCodec.INSTANCE) + .addLast(selectorHandler); + } + })); + pipeline.addLast(new Http3TripleServerConnectionHandler()); + }; + } + public static AbstractConnectionClient connect(URL url) { return CLIENTS.compute(url.getAddress(), (address, client) -> { if (client == null) { + URL clientUrl = url.putAttribute(PIPELINE_CONFIGURATOR_KEY, configClientPipeline(url)); AbstractConnectionClient connectionClient = NEGOTIATION_ENABLED - ? Helper.createAutoSwitchClient(url, HANDLER) - : Helper.createHttp3Client(url, HANDLER); + ? Helper.createAutoSwitchClient(clientUrl, HANDLER) + : Helper.createHttp3Client(clientUrl, HANDLER); connectionClient.addCloseListener(() -> CLIENTS.remove(address, connectionClient)); client = connectionClient; } else { @@ -89,6 +126,16 @@ public static AbstractConnectionClient connect(URL url) { }); } + private static Consumer configClientPipeline(URL url) { + int heartbeat = UrlUtils.getHeartbeat(url); + int closeTimeout = UrlUtils.getCloseTimeout(url); + return pipeline -> { + pipeline.addLast(Http3ClientFrameCodec.INSTANCE); + pipeline.addLast(new IdleStateHandler(heartbeat, 0, 0, TimeUnit.MILLISECONDS)); + pipeline.addLast(new TriplePingPongHandler(closeTimeout)); + }; + } + public static void close() { if (SERVERS.isEmpty()) { return; @@ -99,7 +146,7 @@ public static void close() { try { server.close(); } catch (Throwable t) { - LOGGER.error(LoggerCodeConstants.PROTOCOL_ERROR_CLOSE_SERVER, "", "", "Close Http3 server failed", t); + LOGGER.error(LoggerCodeConstants.PROTOCOL_ERROR_CLOSE_SERVER, "Close http3 server failed", t); } } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleConstants.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleConstants.java index 0635bcbef3f..3cf37a4b120 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleConstants.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleConstants.java @@ -40,5 +40,7 @@ public final class TripleConstants { public static final String TRIPLE_HANDLER_TYPE_REST = "rest"; public static final String TRIPLE_HANDLER_TYPE_GRPC = "grpc"; + public static final String UPGRADE_HEADER_KEY = "Upgrade"; + private TripleConstants() {} } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleHttp2Protocol.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleHttp2Protocol.java index a04f4a9d217..bbd53f4ab15 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleHttp2Protocol.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleHttp2Protocol.java @@ -32,6 +32,9 @@ import org.apache.dubbo.remoting.http12.netty4.h2.NettyHttp2FrameCodec; import org.apache.dubbo.remoting.http12.netty4.h2.NettyHttp2ProtocolSelectorHandler; import org.apache.dubbo.remoting.utils.UrlUtils; +import org.apache.dubbo.remoting.websocket.netty4.WebSocketFrameCodec; +import org.apache.dubbo.remoting.websocket.netty4.WebSocketProtocolSelectorHandler; +import org.apache.dubbo.remoting.websocket.netty4.WebSocketServerUpgradeCodec; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.model.ScopeModelAware; import org.apache.dubbo.rpc.protocol.tri.h12.TripleProtocolDetector; @@ -40,16 +43,23 @@ import org.apache.dubbo.rpc.protocol.tri.transport.TripleGoAwayHandler; import org.apache.dubbo.rpc.protocol.tri.transport.TripleServerConnectionHandler; import org.apache.dubbo.rpc.protocol.tri.transport.TripleTailHandler; +import org.apache.dubbo.rpc.protocol.tri.websocket.DefaultWebSocketServerTransportListenerFactory; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; +import io.netty.handler.codec.http.HttpHeaderValues; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.codec.http.HttpServerUpgradeHandler; +import io.netty.handler.codec.http.websocketx.WebSocketDecoderConfig; +import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolConfig; +import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; +import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler; import io.netty.handler.codec.http2.Http2CodecUtil; import io.netty.handler.codec.http2.Http2FrameCodec; import io.netty.handler.codec.http2.Http2FrameCodecBuilder; @@ -152,6 +162,21 @@ private void configurerHttp1Handlers(URL url, List handlers) { new TripleServerConnectionHandler(), buildHttp2MultiplexHandler(url, tripleConfig), new TripleTailHandler()); + } else if (AsciiString.contentEquals(HttpHeaderValues.WEBSOCKET, protocol)) { + return new WebSocketServerUpgradeCodec( + Arrays.asList( + HttpObjectAggregator.class, + NettyHttp1Codec.class, + NettyHttp1ConnectionHandler.class), + new WebSocketServerCompressionHandler(), + new HttpWriteQueueHandler(), + new WebSocketProtocolSelectorHandler( + url, + frameworkModel, + tripleConfig, + DefaultWebSocketServerTransportListenerFactory.INSTANCE), + buildWebSocketServerProtocolHandler(tripleConfig), + new WebSocketFrameCodec()); } // Not upgrade request return null; @@ -205,4 +230,14 @@ private Http2FrameCodec buildHttp2FrameCodec(TripleConfig tripleConfig) { .validateHeaders(false) .build(); } + + private WebSocketServerProtocolHandler buildWebSocketServerProtocolHandler(TripleConfig tripleConfig) { + return new WebSocketServerProtocolHandler(WebSocketServerProtocolConfig.newBuilder() + .checkStartsWith(true) + .handleCloseFrames(false) + .decoderConfig(WebSocketDecoderConfig.newBuilder() + .maxFramePayloadLength(tripleConfig.getMaxBodySizeOrDefault()) + .build()) + .build()); + } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java index 2df0c748d54..19412dd0109 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java @@ -50,7 +50,9 @@ import static org.apache.dubbo.config.Constants.CLIENT_THREAD_POOL_NAME; import static org.apache.dubbo.config.Constants.SERVER_THREAD_POOL_NAME; import static org.apache.dubbo.rpc.Constants.H2_SETTINGS_IGNORE_1_0_0_KEY; +import static org.apache.dubbo.rpc.Constants.H2_SETTINGS_OPENAPI_ENABLED; import static org.apache.dubbo.rpc.Constants.H2_SETTINGS_RESOLVE_FALLBACK_TO_DEFAULT_KEY; +import static org.apache.dubbo.rpc.Constants.H2_SETTINGS_REST_ENABLED; import static org.apache.dubbo.rpc.Constants.H2_SETTINGS_SUPPORT_NO_LOWER_HEADER_KEY; import static org.apache.dubbo.rpc.Constants.H2_SETTINGS_VERBOSE_ENABLED; @@ -65,12 +67,14 @@ public class TripleProtocol extends AbstractProtocol { public static boolean IGNORE_1_0_0_VERSION = false; public static boolean RESOLVE_FALLBACK_TO_DEFAULT = true; public static boolean VERBOSE_ENABLED = false; + public static boolean REST_ENABLED = true; + public static boolean OPENAPI_ENABLED = false; public TripleProtocol(FrameworkModel frameworkModel) { this.frameworkModel = frameworkModel; triBuiltinService = new TriBuiltinService(frameworkModel); pathResolver = frameworkModel.getDefaultExtension(PathResolver.class); - mappingRegistry = frameworkModel.getBeanFactory().getOrRegisterBean(DefaultRequestMappingRegistry.class); + mappingRegistry = frameworkModel.getOrRegisterBean(DefaultRequestMappingRegistry.class); acceptEncodings = String.join(",", frameworkModel.getSupportedExtensions(DeCompressor.class)); // init env settings @@ -82,6 +86,9 @@ public TripleProtocol(FrameworkModel frameworkModel) { // init global settings Configuration globalConf = ConfigurationUtils.getGlobalConfiguration(frameworkModel.defaultApplication()); VERBOSE_ENABLED = globalConf.getBoolean(H2_SETTINGS_VERBOSE_ENABLED, false); + REST_ENABLED = globalConf.getBoolean(H2_SETTINGS_REST_ENABLED, true); + OPENAPI_ENABLED = globalConf.getBoolean(H2_SETTINGS_OPENAPI_ENABLED, false); + ServletExchanger.init(globalConf); Http3Exchanger.init(globalConf); } @@ -104,7 +111,9 @@ public void afterUnExport() { pathResolver.unregister(invoker); // unregister rest request mapping - mappingRegistry.unregister(invoker); + if (REST_ENABLED) { + mappingRegistry.unregister(invoker); + } // set service status to NOT_SERVING setServiceStatus(url, false); @@ -121,7 +130,9 @@ public void afterUnExport() { pathResolver.register(invoker); // register rest request mapping - mappingRegistry.register(invoker); + if (REST_ENABLED) { + mappingRegistry.register(invoker); + } // set service status to SERVING setServiceStatus(url, true); @@ -205,7 +216,9 @@ public void destroy() { PortUnificationExchanger.close(); Http3Exchanger.close(); pathResolver.destroy(); - mappingRegistry.destroy(); + if (REST_ENABLED) { + mappingRegistry.destroy(); + } super.destroy(); } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerCallListener.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerCallListener.java index 4158649a11d..0a8f1afe8ae 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerCallListener.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerCallListener.java @@ -25,6 +25,8 @@ import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcInvocation; +import org.apache.dubbo.rpc.RpcServiceContext; +import org.apache.dubbo.rpc.protocol.tri.TripleConstants; import org.apache.dubbo.rpc.protocol.tri.TripleHeaderEnum; import java.net.InetSocketAddress; @@ -56,14 +58,19 @@ public void invoke() { RpcContext.restoreCancellationContext( ((Http2CancelableStreamObserver) responseObserver).getCancellationContext()); } - InetSocketAddress remoteAddress = - (InetSocketAddress) invocation.getAttributes().remove(REMOTE_ADDRESS_KEY); - RpcContext.getServiceContext().setRemoteAddress(remoteAddress); - String remoteApp = (String) invocation.getAttributes().remove(TripleHeaderEnum.CONSUMER_APP_NAME_KEY); + + RpcServiceContext serviceContext = RpcContext.getServiceContext(); + serviceContext.setRemoteAddress((InetSocketAddress) invocation.remove(REMOTE_ADDRESS_KEY)); + String remoteApp = (String) invocation.remove(TripleHeaderEnum.CONSUMER_APP_NAME_KEY); if (remoteApp != null) { - RpcContext.getServiceContext().setRemoteApplicationName(remoteApp); + serviceContext.setRemoteApplicationName(remoteApp); invocation.setAttachmentIfAbsent(REMOTE_APPLICATION_KEY, remoteApp); } + if (serviceContext.getRequest() == null) { + serviceContext.setRequest(invocation.get(TripleConstants.HTTP_REQUEST_KEY)); + serviceContext.setResponse(invocation.get(TripleConstants.HTTP_RESPONSE_KEY)); + } + try { long stInMillis = System.currentTimeMillis(); Result response = invoker.invoke(invocation); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java index 871b9aa46b9..15ef4a0fc6e 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java @@ -23,6 +23,7 @@ import org.apache.dubbo.common.threadpool.manager.ExecutorRepository; import org.apache.dubbo.common.threadpool.serial.SerializingExecutor; import org.apache.dubbo.common.utils.MethodUtils; +import org.apache.dubbo.common.utils.UrlUtils; import org.apache.dubbo.remoting.http12.HttpChannel; import org.apache.dubbo.remoting.http12.HttpInputMessage; import org.apache.dubbo.remoting.http12.HttpStatus; @@ -61,7 +62,6 @@ public abstract class AbstractServerTransportListener
headerFilters; private Executor executor; private HEADER httpMetadata; @@ -72,11 +72,8 @@ protected AbstractServerTransportListener(FrameworkModel frameworkModel, URL url this.frameworkModel = frameworkModel; this.url = url; this.httpChannel = httpChannel; - requestRouter = frameworkModel.getBeanFactory().getOrRegisterBean(DefaultRequestRouter.class); + requestRouter = frameworkModel.getOrRegisterBean(DefaultRequestRouter.class); exceptionCustomizerWrapper = new ExceptionCustomizerWrapper(frameworkModel); - headerFilters = frameworkModel - .getExtensionLoader(HeaderFilter.class) - .getActivateExtension(url, CommonConstants.HEADER_FILTER_KEY); } @Override @@ -278,14 +275,27 @@ protected final RpcInvocation buildRpcInvocation(RpcInvocationBuildContext conte if (consumerAppName != null) { inv.put(TripleHeaderEnum.CONSUMER_APP_NAME_KEY, consumerAppName); } + // customizer RpcInvocation - headerFilters.forEach(f -> f.invoke(invoker, inv)); + HeaderFilter[] headerFilters = + UrlUtils.computeServiceAttribute(invoker.getUrl(), HEADER_FILTERS_CACHE, this::loadHeaderFilters); + for (HeaderFilter headerFilter : headerFilters) { + headerFilter.invoke(invoker, inv); + } initializeAltSvc(url); return onBuildRpcInvocationCompletion(inv); } + private HeaderFilter[] loadHeaderFilters(URL url) { + List headerFilters = frameworkModel + .getExtensionLoader(HeaderFilter.class) + .getActivateExtension(url, CommonConstants.HEADER_FILTER_KEY); + LOGGER.info("Header filters for [{}] loaded: {}", url, headerFilters); + return headerFilters.toArray(new HeaderFilter[0]); + } + protected RpcInvocation onBuildRpcInvocationCompletion(RpcInvocation invocation) { String timeoutString = httpMetadata.header(TripleHeaderEnum.SERVICE_TIMEOUT.getKey()); try { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/CompositeExceptionHandler.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/CompositeExceptionHandler.java index 493b0f6ef94..f9d32724056 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/CompositeExceptionHandler.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/CompositeExceptionHandler.java @@ -62,16 +62,7 @@ public Level resolveLogLevel(Throwable throwable) { } } - if (throwable instanceof HttpStatusException) { - int httpStatusCode = ((HttpStatusException) throwable).getStatusCode(); - if (httpStatusCode < HttpStatus.BAD_REQUEST.getCode()) { - return TripleProtocol.VERBOSE_ENABLED ? Level.INFO : Level.DEBUG; - } - if (httpStatusCode < HttpStatus.INTERNAL_SERVER_ERROR.getCode()) { - return Level.INFO; - } - } - return Level.ERROR; + return ExceptionUtils.resolveLogLevel(throwable); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/ExceptionCustomizerWrapper.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/ExceptionCustomizerWrapper.java index ddb599f1cd5..b740de8ddf6 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/ExceptionCustomizerWrapper.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/ExceptionCustomizerWrapper.java @@ -38,7 +38,7 @@ public final class ExceptionCustomizerWrapper { private boolean needWrap; public ExceptionCustomizerWrapper(FrameworkModel frameworkModel) { - exceptionHandler = frameworkModel.getBeanFactory().getOrRegisterBean(CompositeExceptionHandler.class); + exceptionHandler = frameworkModel.getOrRegisterBean(CompositeExceptionHandler.class); } public void setMetadata(RequestMetadata metadata) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/HttpContextCallbackFilter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/HttpContextCallbackFilter.java index 1ae5603e5e1..fa482948956 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/HttpContextCallbackFilter.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/HttpContextCallbackFilter.java @@ -29,7 +29,7 @@ import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.protocol.tri.TripleConstants; -@Activate(group = CommonConstants.PROVIDER, order = 29000) +@Activate(group = CommonConstants.PROVIDER, order = 10) public class HttpContextCallbackFilter implements Filter, BaseFilter.Listener { @Override @@ -58,13 +58,12 @@ public void onResponse(Result appResponse, Invoker invoker, Invocation invoca if (response.isEmpty()) { return; } - if (response.isContentEmpty()) { - if (appResponse.hasException()) { - return; + if (!response.isCommitted()) { + if (response.isContentEmpty()) { + response.setBody(appResponse.hasException() ? appResponse.getException() : appResponse.getValue()); } - response.setBody(appResponse.getValue()); + response.commit(); } - response.commit(); HttpResult result = response.toHttpResult(); if (result.getBody() instanceof Throwable) { appResponse.setException((Throwable) result.getBody()); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/DefaultHttp11ServerTransportListener.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/DefaultHttp11ServerTransportListener.java index e59cb07421d..5e03be4c404 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/DefaultHttp11ServerTransportListener.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/DefaultHttp11ServerTransportListener.java @@ -24,8 +24,8 @@ import org.apache.dubbo.remoting.http12.HttpInputMessage; import org.apache.dubbo.remoting.http12.RequestMetadata; import org.apache.dubbo.remoting.http12.h1.Http1ServerChannelObserver; -import org.apache.dubbo.remoting.http12.h1.Http1ServerStreamChannelObserver; import org.apache.dubbo.remoting.http12.h1.Http1ServerTransportListener; +import org.apache.dubbo.remoting.http12.h1.Http1SseServerChannelObserver; import org.apache.dubbo.remoting.http12.message.DefaultListeningDecoder; import org.apache.dubbo.remoting.http12.message.MediaType; import org.apache.dubbo.remoting.http12.message.codec.JsonCodec; @@ -81,9 +81,9 @@ private ServerCallListener startListener( case UNARY: return new AutoCompleteUnaryServerCallListener(invocation, invoker, responseObserver); case SERVER_STREAM: - responseObserver = prepareResponseObserver(new Http1ServerStreamChannelObserver(httpChannel)); + responseObserver = prepareResponseObserver(new Http1SseServerChannelObserver(httpChannel)); responseObserver.addHeadersCustomizer((hs, t) -> - hs.set(HttpHeaderNames.CONTENT_TYPE.getName(), MediaType.TEXT_EVENT_STREAM.getName())); + hs.set(HttpHeaderNames.CONTENT_TYPE.getKey(), MediaType.TEXT_EVENT_STREAM.getName())); return new AutoCompleteServerStreamServerCallListener(invocation, invoker, responseObserver); default: throw new UnsupportedOperationException("HTTP1.x only support unary and server-stream"); @@ -104,7 +104,7 @@ protected void onError(Throwable throwable) { protected void initializeAltSvc(URL url) { String protocolId = Http3Exchanger.isEnabled(url) ? "h3" : "h2"; String value = protocolId + "=\":" + url.getParameter(Constants.BIND_PORT_KEY, url.getPort()) + '"'; - responseObserver.addHeadersCustomizer((hs, t) -> hs.set(HttpHeaderNames.ALT_SVC.getName(), value)); + responseObserver.addHeadersCustomizer((hs, t) -> hs.set(HttpHeaderNames.ALT_SVC.getKey(), value)); } private static final class AutoCompleteUnaryServerCallListener extends UnaryServerCallListener { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/Http1UnaryServerChannelObserver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/Http1UnaryServerChannelObserver.java index eff04e89072..1aa994de525 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/Http1UnaryServerChannelObserver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/Http1UnaryServerChannelObserver.java @@ -24,6 +24,9 @@ import org.apache.dubbo.rpc.protocol.tri.ExceptionUtils; import org.apache.dubbo.rpc.protocol.tri.TripleProtocol; +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; + import io.netty.buffer.ByteBufOutputStream; public final class Http1UnaryServerChannelObserver extends Http1ServerChannelObserver { @@ -52,8 +55,18 @@ protected void doOnError(Throwable throwable) throws Throwable { @Override protected void customizeHeaders(HttpHeaders headers, Throwable throwable, HttpOutputMessage message) { super.customizeHeaders(headers, throwable, message); - int contentLength = message == null ? 0 : ((ByteBufOutputStream) message.getBody()).writtenBytes(); - headers.set(HttpHeaderNames.CONTENT_LENGTH.getName(), String.valueOf(contentLength)); + int contentLength = 0; + if (message != null) { + OutputStream body = message.getBody(); + if (body instanceof ByteBufOutputStream) { + contentLength = ((ByteBufOutputStream) body).writtenBytes(); + } else if (body instanceof ByteArrayOutputStream) { + contentLength = ((ByteArrayOutputStream) body).size(); + } else { + throw new IllegalArgumentException("Unsupported body type: " + body.getClass()); + } + } + headers.set(HttpHeaderNames.CONTENT_LENGTH.getKey(), String.valueOf(contentLength)); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/GenericHttp2ServerTransportListener.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/GenericHttp2ServerTransportListener.java index 9f395c55073..f4f0aeefb3d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/GenericHttp2ServerTransportListener.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/GenericHttp2ServerTransportListener.java @@ -28,6 +28,7 @@ import org.apache.dubbo.remoting.http12.message.DefaultListeningDecoder; import org.apache.dubbo.remoting.http12.message.DefaultStreamingDecoder; import org.apache.dubbo.remoting.http12.message.ListeningDecoder; +import org.apache.dubbo.remoting.http12.message.MediaType; import org.apache.dubbo.remoting.http12.message.StreamingDecoder; import org.apache.dubbo.remoting.http12.message.codec.JsonCodec; import org.apache.dubbo.rpc.Invoker; @@ -71,7 +72,11 @@ protected Http2ServerChannelObserver newResponseObserver(H2StreamChannel h2Strea } protected Http2ServerChannelObserver newStreamResponseObserver(H2StreamChannel h2StreamChannel) { - return new Http2StreamServerChannelObserver(getFrameworkModel(), h2StreamChannel); + Http2ServerChannelObserver responseObserver = + new Http2SseServerChannelObserver(getFrameworkModel(), h2StreamChannel); + responseObserver.addHeadersCustomizer( + (hs, t) -> hs.set(HttpHeaderNames.CONTENT_TYPE.getKey(), MediaType.TEXT_EVENT_STREAM.getName())); + return responseObserver; } protected Http2ServerChannelObserver prepareResponseObserver(Http2ServerChannelObserver responseObserver) { @@ -124,7 +129,7 @@ protected void prepareStreamServerCall() { protected void initializeAltSvc(URL url) { if (Http3Exchanger.isEnabled(url)) { String value = "h3=\":" + url.getParameter(Constants.BIND_PORT_KEY, url.getPort()) + '"'; - responseObserver.addHeadersCustomizer((hs, t) -> hs.set(HttpHeaderNames.ALT_SVC.getName(), value)); + responseObserver.addHeadersCustomizer((hs, t) -> hs.set(HttpHeaderNames.ALT_SVC.getKey(), value)); } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2SseServerChannelObserver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2SseServerChannelObserver.java new file mode 100644 index 00000000000..b36dc5e3536 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2SseServerChannelObserver.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.dubbo.rpc.protocol.tri.h12.http2; + +import org.apache.dubbo.remoting.http12.HttpConstants; +import org.apache.dubbo.remoting.http12.HttpHeaderNames; +import org.apache.dubbo.remoting.http12.HttpMetadata; +import org.apache.dubbo.remoting.http12.HttpOutputMessage; +import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; +import org.apache.dubbo.rpc.model.FrameworkModel; + +import java.io.IOException; + +public final class Http2SseServerChannelObserver extends Http2StreamServerChannelObserver { + + public Http2SseServerChannelObserver(FrameworkModel frameworkModel, H2StreamChannel h2StreamChannel) { + super(frameworkModel, h2StreamChannel); + } + + @Override + protected HttpMetadata encodeHttpMetadata(boolean endStream) { + return super.encodeHttpMetadata(endStream) + .header(HttpHeaderNames.CACHE_CONTROL.getKey(), HttpConstants.NO_CACHE); + } + + @Override + protected void preOutputMessage(HttpOutputMessage message) throws IOException { + HttpOutputMessage prefixMessage = getHttpChannel().newOutputMessage(); + prefixMessage.getBody().write(HttpConstants.SERVER_SENT_EVENT_DATA_PREFIX_BYTES); + getHttpChannel().writeMessage(prefixMessage); + } + + @Override + protected void postOutputMessage(HttpOutputMessage message) throws IOException { + HttpOutputMessage lfMessage = getHttpChannel().newOutputMessage(); + lfMessage.getBody().write(HttpConstants.SERVER_SENT_EVENT_LF_BYTES); + getHttpChannel().writeMessage(lfMessage); + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/Http3ClientFrameCodec.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/Http3ClientFrameCodec.java index 11ef9da285e..da4e9cd9e99 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/Http3ClientFrameCodec.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/Http3ClientFrameCodec.java @@ -16,6 +16,10 @@ */ package org.apache.dubbo.rpc.protocol.tri.h3; +import org.apache.dubbo.common.logger.FluentLogger; +import org.apache.dubbo.remoting.http12.HttpConstants; +import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.remoting.http3.netty4.Constants; import org.apache.dubbo.remoting.http3.netty4.Http2HeadersAdapter; import org.apache.dubbo.remoting.http3.netty4.Http3HeadersAdapter; import org.apache.dubbo.rpc.protocol.tri.TripleHeaderEnum; @@ -24,33 +28,49 @@ import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPromise; import io.netty.handler.codec.http2.DefaultHttp2DataFrame; import io.netty.handler.codec.http2.DefaultHttp2GoAwayFrame; import io.netty.handler.codec.http2.DefaultHttp2HeadersFrame; +import io.netty.handler.codec.http2.DefaultHttp2PingFrame; import io.netty.handler.codec.http2.DefaultHttp2ResetFrame; import io.netty.handler.codec.http2.Http2DataFrame; +import io.netty.handler.codec.http2.Http2Headers.PseudoHeaderName; import io.netty.handler.codec.http2.Http2HeadersFrame; +import io.netty.handler.codec.http2.Http2PingFrame; import io.netty.incubator.codec.http3.DefaultHttp3DataFrame; +import io.netty.incubator.codec.http3.DefaultHttp3Headers; import io.netty.incubator.codec.http3.DefaultHttp3HeadersFrame; +import io.netty.incubator.codec.http3.Http3; import io.netty.incubator.codec.http3.Http3DataFrame; import io.netty.incubator.codec.http3.Http3ErrorCode; import io.netty.incubator.codec.http3.Http3Exception; import io.netty.incubator.codec.http3.Http3GoAwayFrame; +import io.netty.incubator.codec.http3.Http3Headers; import io.netty.incubator.codec.http3.Http3HeadersFrame; +import io.netty.incubator.codec.http3.Http3RequestStreamInitializer; +import io.netty.incubator.codec.quic.QuicChannel; import io.netty.incubator.codec.quic.QuicStreamChannel; +import static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_RECONNECT; + @Sharable public class Http3ClientFrameCodec extends ChannelDuplexHandler { + private static final FluentLogger LOGGER = FluentLogger.of(Http3ClientFrameCodec.class); public static final Http3ClientFrameCodec INSTANCE = new Http3ClientFrameCodec(); @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { if (msg instanceof Http3HeadersFrame) { - Http2HeadersAdapter headers = new Http2HeadersAdapter(((Http3HeadersFrame) msg).headers()); - boolean endStream = headers.contains(TripleHeaderEnum.STATUS_KEY.getKey()); - ctx.fireChannelRead(new DefaultHttp2HeadersFrame(headers, endStream)); + Http3Headers headers = ((Http3HeadersFrame) msg).headers(); + if (headers.contains(Constants.TRI_PING)) { + pingAck(ctx); + } else { + boolean endStream = headers.contains(TripleHeaderEnum.STATUS_KEY.getKey()); + ctx.fireChannelRead(new DefaultHttp2HeadersFrame(new Http2HeadersAdapter(headers), endStream)); + } } else if (msg instanceof Http3DataFrame) { ctx.fireChannelRead(new DefaultHttp2DataFrame(((Http3DataFrame) msg).content())); } else if (msg instanceof Http3GoAwayFrame) { @@ -60,9 +80,19 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) { } } + private void pingAck(ChannelHandlerContext ctx) { + ChannelPipeline pipeline = ctx.channel().parent().pipeline(); + pipeline.fireChannelRead(new DefaultHttp2PingFrame(0, true)); + pipeline.fireChannelReadComplete(); + } + @Override public void channelReadComplete(ChannelHandlerContext ctx) { - ctx.fireChannelRead(new DefaultHttp2DataFrame(Unpooled.EMPTY_BUFFER, true)); + if (ctx instanceof QuicStreamChannel) { + ctx.fireChannelRead(new DefaultHttp2DataFrame(Unpooled.EMPTY_BUFFER, true)); + } else { + ctx.fireChannelReadComplete(); + } } @Override @@ -80,11 +110,38 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) return; } ctx.write(new DefaultHttp3DataFrame(frame.content()), promise); + } else if (msg instanceof Http2PingFrame) { + sendPing((QuicChannel) ctx.channel()); } else { ctx.write(msg, promise); } } + private void sendPing(QuicChannel channel) { + Http3.newRequestStream(channel, new Http3RequestStreamInitializer() { + @Override + protected void initRequestStream(QuicStreamChannel ch) { + ch.pipeline().addLast(INSTANCE); + } + }) + .addListener(future -> { + if (future.isSuccess()) { + QuicStreamChannel streamChannel = (QuicStreamChannel) future.getNow(); + + Http3Headers header = new DefaultHttp3Headers(false); + header.set(PseudoHeaderName.METHOD.value(), HttpMethods.OPTIONS.name()); + header.set(PseudoHeaderName.PATH.value(), "*"); + header.set(PseudoHeaderName.SCHEME.value(), HttpConstants.HTTPS); + header.set(Constants.TRI_PING, "0"); + + streamChannel.write(new DefaultHttp3HeadersFrame(header)); + streamChannel.shutdownOutput(); + } else { + LOGGER.warn(TRANSPORT_FAILED_RECONNECT, "Failed to send ping frame", future.cause()); + } + }); + } + @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { if (cause instanceof Http3Exception) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/Http3TripleServerConnectionHandler.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/Http3TripleServerConnectionHandler.java new file mode 100644 index 00000000000..afcd19e48c3 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/Http3TripleServerConnectionHandler.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.dubbo.rpc.protocol.tri.h3; + +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPromise; +import io.netty.incubator.codec.http3.Http3GoAwayFrame; +import io.netty.util.ReferenceCountUtil; + +public class Http3TripleServerConnectionHandler extends ChannelDuplexHandler { + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + if (msg instanceof Http3GoAwayFrame) { + ReferenceCountUtil.release(msg); + return; + } + super.channelRead(ctx, msg); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + super.channelInactive(ctx); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + super.exceptionCaught(ctx, cause); + } + + @Override + public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception { + super.close(ctx, promise); + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3ServerTransportListenerFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3ServerTransportListenerFactory.java index 10b622d9a7a..9d0e3437797 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3ServerTransportListenerFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3ServerTransportListenerFactory.java @@ -17,6 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.h3.grpc; import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.constants.CommonConstants; import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.remoting.http3.Http3ServerTransportListenerFactory; @@ -24,7 +25,7 @@ import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.h12.grpc.GrpcUtils; -@Activate(order = -100, onClass = "com.google.protobuf.Message") +@Activate(order = -100, onClass = CommonConstants.PROTOBUF_MESSAGE_CLASS_NAME) public class GrpcHttp3ServerTransportListenerFactory implements Http3ServerTransportListenerFactory { @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/negotiation/AutoSwitchConnectionClient.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/negotiation/AutoSwitchConnectionClient.java index baffe375a12..2431cb9b463 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/negotiation/AutoSwitchConnectionClient.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/negotiation/AutoSwitchConnectionClient.java @@ -18,7 +18,6 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.utils.ClassUtils; import org.apache.dubbo.common.utils.NamedThreadFactory; import org.apache.dubbo.common.utils.NetUtils; @@ -33,11 +32,9 @@ import java.util.concurrent.atomic.AtomicBoolean; import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_ERROR_CLOSE_CLIENT; -import static org.apache.dubbo.common.logger.LoggerFactory.getErrorTypeAwareLogger; public class AutoSwitchConnectionClient extends AbstractConnectionClient { - private static final ErrorTypeAwareLogger LOGGER = getErrorTypeAwareLogger(AutoSwitchConnectionClient.class); private static final int MAX_RETRIES = 8; private final URL url; @@ -58,8 +55,8 @@ public AutoSwitchConnectionClient(URL url, AbstractConnectionClient connectionCl ClassLoader tccl = Thread.currentThread().getContextClassLoader(); connectionClient.addConnectedListener(() -> ClassUtils.runWith(tccl, () -> executor.execute(this::negotiate))); increase(); - if (LOGGER.isInfoEnabled()) { - LOGGER.info( + if (logger.isInfoEnabled()) { + logger.info( "Start HTTP/3 AutoSwitchConnectionClient {} connect to the server {}", NetUtils.getLocalAddress(), url.toInetSocketAddress()); @@ -80,14 +77,14 @@ private void negotiate() { if (clientCall == null) { clientCall = new NegotiateClientCall(connectionClient, executor); } - LOGGER.info("Start HTTP/3 negotiation for [{}]", getBaseUrl()); + logger.info("Start HTTP/3 negotiation for [{}]", getBaseUrl()); clientCall.start(url).whenComplete((altSvc, t) -> { if (t == null) { if (altSvc.contains("h3=")) { negotiateSuccess(); return; } - LOGGER.info( + logger.info( "HTTP/3 negotiation succeed, but provider reply alt-svc='{}' not support HTTP/3 for [{}]", altSvc, getBaseUrl()); @@ -101,7 +98,7 @@ private void negotiate() { private void negotiateSuccess() { negotiated = true; - LOGGER.info("HTTP/3 negotiation succeed for [{}], create http3 client", getBaseUrl()); + logger.info("HTTP/3 negotiation succeed for [{}], create http3 client", getBaseUrl()); http3ConnectionClient = Helper.createHttp3Client(url, connectionClient.getDelegateHandler()); http3ConnectionClient.addConnectedListener(() -> setHttp3Connected(true)); http3ConnectionClient.addDisconnectedListener(() -> setHttp3Connected(false)); @@ -111,11 +108,11 @@ private void negotiateSuccess() { private void reScheduleNegotiate(Throwable t) { if (attempt++ < MAX_RETRIES) { int delay = 1 << attempt + 2; - LOGGER.info("HTTP/3 negotiation failed, retry after {} seconds for [{}]", delay, getBaseUrl(), t); + logger.info("HTTP/3 negotiation failed, retry after {} seconds for [{}]", delay, getBaseUrl(), t); executor.schedule(this::negotiate, delay, TimeUnit.SECONDS); return; } - LOGGER.warn( + logger.warn( PROTOCOL_ERROR_CLOSE_CLIENT, "", "", @@ -133,7 +130,7 @@ private void negotiateEnd() { private void setHttp3Connected(boolean http3Connected) { this.http3Connected = http3Connected; - LOGGER.info("Switch protocol to {} for [{}]", http3Connected ? "HTTP/3" : "HTTP/2", url.toString("")); + logger.info("Switch protocol to {} for [{}]", http3Connected ? "HTTP/3" : "HTTP/2", url.toString("")); } public boolean isHttp3Connected() { @@ -155,13 +152,13 @@ public boolean release() { try { connectionClient.release(); } catch (Throwable t) { - LOGGER.warn(PROTOCOL_ERROR_CLOSE_CLIENT, "", "", t.getMessage(), t); + logger.warn(PROTOCOL_ERROR_CLOSE_CLIENT, "", "", t.getMessage(), t); } if (http3ConnectionClient != null) { try { http3ConnectionClient.release(); } catch (Throwable t) { - LOGGER.warn(PROTOCOL_ERROR_CLOSE_CLIENT, "", "", t.getMessage(), t); + logger.warn(PROTOCOL_ERROR_CLOSE_CLIENT, "", "", t.getMessage(), t); } } return true; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/negotiation/NegotiateClientCall.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/negotiation/NegotiateClientCall.java index 54db142391b..2b3f629b814 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/negotiation/NegotiateClientCall.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/negotiation/NegotiateClientCall.java @@ -59,6 +59,10 @@ public CompletableFuture start(URL url) { CompletableFuture future = new CompletableFuture<>(); try { Channel channel = connectionClient.getChannel(true); + if (channel == null) { + future.completeExceptionally(new IllegalStateException("Channel is null")); + return future; + } Http2StreamChannelBootstrap bootstrap = new Http2StreamChannelBootstrap(channel); bootstrap.handler(new ChannelInboundHandlerAdapter() { @Override @@ -112,9 +116,6 @@ private static final class Listener implements H2TransportListener { @Override public void onHeader(Http2Headers headers, boolean endStream) { - if (endStream) { - return; - } CharSequence line = headers.status(); if (line != null) { HttpResponseStatus status = HttpResponseStatus.parseLine(line); @@ -124,6 +125,9 @@ public void onHeader(Http2Headers headers, boolean endStream) { return; } } + if (endStream) { + return; + } executor.execute(() -> future.completeExceptionally(new RuntimeException("Status: " + line))); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestConstants.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestConstants.java index fc368005345..bb754e24c32 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestConstants.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestConstants.java @@ -49,19 +49,6 @@ public final class RestConstants { /* Configuration Key */ public static final String CONFIG_PREFIX = "dubbo.protocol.triple.rest."; - public static final String SUFFIX_PATTERN_MATCH_KEY = CONFIG_PREFIX + "suffix-pattern-match"; - public static final String TRAILING_SLASH_MATCH_KEY = CONFIG_PREFIX + "trailing-slash-match"; - public static final String CASE_SENSITIVE_MATCH_KEY = CONFIG_PREFIX + "case-sensitive-match"; - public static final String FORMAT_PARAMETER_NAME_KEY = CONFIG_PREFIX + "format-parameter-name"; - - /* Cors Configuration Key */ - public static final String CORS_CONFIG_PREFIX = CONFIG_PREFIX + "cors."; - public static final String ALLOWED_ORIGINS = CORS_CONFIG_PREFIX + "allowed-origins"; - public static final String ALLOWED_METHODS = CORS_CONFIG_PREFIX + "allowed-methods"; - public static final String ALLOWED_HEADERS = CORS_CONFIG_PREFIX + "allowed-headers"; - public static final String ALLOW_CREDENTIALS = CORS_CONFIG_PREFIX + "allow-credentials"; - public static final String EXPOSED_HEADERS = CORS_CONFIG_PREFIX + "exposed-headers"; - public static final String MAX_AGE = CORS_CONFIG_PREFIX + "max-age"; private RestConstants() {} } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestHttpMessageCodec.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestHttpMessageCodec.java index cd6df6f4d69..653794d4b92 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestHttpMessageCodec.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestHttpMessageCodec.java @@ -35,6 +35,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.Charset; +import java.util.Optional; public final class RestHttpMessageCodec implements HttpMessageDecoder, HttpMessageEncoder { @@ -110,6 +111,10 @@ private InputStream decodeInputStream(InputStream is) { public void encode(OutputStream os, Object data) throws EncodeException { if (data != null) { Class type = data.getClass(); + if (type == Optional.class) { + encode(os, ((Optional) data).orElse(null)); + return; + } try { if (type == byte[].class) { os.write((byte[]) data); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AbstractAnnotationBaseArgumentResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AbstractAnnotationBaseArgumentResolver.java index 9b9143e0a70..9a980a1da7e 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AbstractAnnotationBaseArgumentResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AbstractAnnotationBaseArgumentResolver.java @@ -33,10 +33,13 @@ public Object resolve( AnnotationMeta annotation, HttpRequest request, HttpResponse response) { - NamedValueMeta namedValue = - cache.computeIfAbsent(parameter, k -> updateNamedValueMeta(k, createNamedValueMeta(k, annotation))); - return resolve(namedValue, request, response); + return resolve(getNamedValueMeta(parameter, annotation), request, response); } - protected abstract NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann); + @Override + public final NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta annotation) { + return cache.computeIfAbsent(parameter, k -> updateNamedValueMeta(k, createNamedValueMeta(k, annotation))); + } + + protected abstract NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta anno); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AbstractArgumentResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AbstractArgumentResolver.java index 6675f1e5809..7064d5df4b5 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AbstractArgumentResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AbstractArgumentResolver.java @@ -25,9 +25,11 @@ public abstract class AbstractArgumentResolver extends NamedValueArgumentResolve @Override public Object resolve(ParameterMeta parameter, HttpRequest request, HttpResponse response) { - NamedValueMeta namedValue = - cache.computeIfAbsent(parameter, k -> updateNamedValueMeta(k, createNamedValueMeta(k))); - return resolve(namedValue, request, response); + return resolve(getNamedValueMeta(parameter), request, response); + } + + public final NamedValueMeta getNamedValueMeta(ParameterMeta parameter) { + return cache.computeIfAbsent(parameter, k -> updateNamedValueMeta(k, createNamedValueMeta(k))); } protected abstract NamedValueMeta createNamedValueMeta(ParameterMeta parameter); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AnnotationBaseArgumentResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AnnotationBaseArgumentResolver.java index 30b7a12205d..060b97c7cd7 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AnnotationBaseArgumentResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AnnotationBaseArgumentResolver.java @@ -19,6 +19,7 @@ import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import java.lang.annotation.Annotation; @@ -27,6 +28,8 @@ public interface AnnotationBaseArgumentResolver extends Ar Class accept(); + NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta annotation); + Object resolve(ParameterMeta parameter, AnnotationMeta annotation, HttpRequest request, HttpResponse response); default boolean accept(ParameterMeta parameter) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/CompositeArgumentConverter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/CompositeArgumentConverter.java index 6dd685706a4..2799b1b60b5 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/CompositeArgumentConverter.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/CompositeArgumentConverter.java @@ -22,10 +22,9 @@ import org.apache.dubbo.common.utils.Pair; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.TypeParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils; -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -114,29 +113,4 @@ private List getSuitableConverters(Class sourceType, Class ta return result; }); } - - private static final class TypeParameterMeta extends ParameterMeta { - - private final Class type; - - TypeParameterMeta(Class type) { - super(null, null); - this.type = type; - } - - @Override - public Class getType() { - return type; - } - - @Override - public Type getGenericType() { - return type; - } - - @Override - protected AnnotatedElement getAnnotatedElement() { - return Object.class; - } - } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/CompositeArgumentResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/CompositeArgumentResolver.java index 69c50585bc6..a3a4a77bd71 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/CompositeArgumentResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/CompositeArgumentResolver.java @@ -18,9 +18,11 @@ import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import java.util.ArrayList; @@ -50,6 +52,10 @@ public CompositeArgumentResolver(FrameworkModel frameworkModel) { argumentConverter = new CompositeArgumentConverter(frameworkModel); } + public ArgumentConverter getArgumentConverter() { + return argumentConverter; + } + @Override public boolean accept(ParameterMeta parameter) { return true; @@ -57,14 +63,14 @@ public boolean accept(ParameterMeta parameter) { @Override public Object resolve(ParameterMeta parameter, HttpRequest request, HttpResponse response) { - AnnotationMeta[] annotations = parameter.findAnnotations(); - for (AnnotationMeta annotation : annotations) { + for (AnnotationMeta annotation : parameter.findAnnotations()) { AnnotationBaseArgumentResolver resolver = resolverMap.get(annotation.getAnnotationType()); if (resolver != null) { Object value = resolver.resolve(parameter, annotation, request, response); return argumentConverter.convert(value, parameter); } } + for (ArgumentResolver resolver : resolvers) { if (resolver.accept(parameter)) { Object value = resolver.resolve(parameter, request, response); @@ -75,7 +81,24 @@ public Object resolve(ParameterMeta parameter, HttpRequest request, HttpResponse throw new IllegalStateException(Messages.ARGUMENT_COULD_NOT_RESOLVED.format(parameter.getDescription())); } - public ArgumentConverter getArgumentConverter() { - return argumentConverter; + public NamedValueMeta getNamedValueMeta(ParameterMeta parameter) { + for (AnnotationMeta annotation : parameter.findAnnotations()) { + AnnotationBaseArgumentResolver resolver = resolverMap.get(annotation.getAnnotationType()); + if (resolver != null) { + return resolver.getNamedValueMeta(parameter, annotation); + } + } + + for (ArgumentResolver resolver : resolvers) { + if (resolver.accept(parameter)) { + if (resolver instanceof AbstractArgumentResolver) { + return ((AbstractArgumentResolver) resolver).getNamedValueMeta(parameter); + } else { + return new NamedValueMeta().setParamType(ParamType.Attribute); + } + } + } + + return null; } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/GeneralTypeConverter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/GeneralTypeConverter.java index eaededb5f9f..c950aa64c15 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/GeneralTypeConverter.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/GeneralTypeConverter.java @@ -16,7 +16,6 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.argument; -import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; import org.apache.dubbo.common.io.StreamUtils; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; @@ -114,10 +113,9 @@ public class GeneralTypeConverter implements TypeConverter { private final HttpJsonUtils httpJsonUtils; public GeneralTypeConverter(FrameworkModel frameworkModel) { - ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory(); - converter = beanFactory.getOrRegisterBean(CompositeArgumentConverter.class); - codecUtils = beanFactory.getOrRegisterBean(CodecUtils.class); - httpJsonUtils = beanFactory.getOrRegisterBean(HttpJsonUtils.class); + converter = frameworkModel.getOrRegisterBean(CompositeArgumentConverter.class); + codecUtils = frameworkModel.getOrRegisterBean(CodecUtils.class); + httpJsonUtils = frameworkModel.getOrRegisterBean(HttpJsonUtils.class); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/NamedValueArgumentResolverSupport.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/NamedValueArgumentResolverSupport.java index f69402fd9e8..e5c701449b6 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/NamedValueArgumentResolverSupport.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/NamedValueArgumentResolverSupport.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestParameterException; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; @@ -45,7 +46,6 @@ protected final Object resolve(NamedValueMeta meta, HttpRequest request, HttpRes if (arg != null) { return filterValue(arg, meta); } - arg = meta.defaultValue(); if (arg != null) { return arg; @@ -56,23 +56,29 @@ protected final Object resolve(NamedValueMeta meta, HttpRequest request, HttpRes return null; } - protected final NamedValueMeta updateNamedValueMeta(ParameterMeta parameterMeta, NamedValueMeta meta) { + protected final NamedValueMeta updateNamedValueMeta(ParameterMeta parameter, NamedValueMeta meta) { if (meta.isNameEmpty()) { - meta.setName(parameterMeta.getName()); + meta.setName(parameter.getName()); } - - Class type = parameterMeta.getActualType(); + if (meta.paramType() == null) { + meta.setParamType(getParamType(meta)); + } + Class type = parameter.getActualType(); meta.setType(type); - meta.setGenericType(parameterMeta.getActualGenericType()); + meta.setGenericType(parameter.getActualGenericType()); if (type.isArray()) { meta.setNestedTypes(new Class[] {type}); } else { meta.setNestedTypes(TypeUtils.getNestedActualTypes(meta.genericType())); } - meta.setParameterMeta(parameterMeta); + meta.setParameter(parameter); return meta; } + protected ParamType getParamType(NamedValueMeta meta) { + return null; + } + protected String emptyDefaultValue(NamedValueMeta meta) { return meta.defaultValue(); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/cors/CorsUtils.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/cors/CorsUtils.java index a71cf9ec00e..b6f31cc0984 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/cors/CorsUtils.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/cors/CorsUtils.java @@ -16,23 +16,16 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.cors; -import org.apache.dubbo.common.config.Configuration; -import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.common.utils.StringUtils; -import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.config.nested.CorsConfig; -import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.config.nested.RestConfig; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.CorsMeta; public class CorsUtils { private CorsUtils() {} - public static CorsMeta getGlobalCorsMeta(FrameworkModel frameworkModel) { - CorsConfig config = ConfigManager.getProtocolOrDefault(CommonConstants.TRIPLE) - .getTripleOrDefault() - .getRestOrDefault() - .getCorsOrDefault(); + public static CorsMeta getGlobalCorsMeta(RestConfig restConfig) { + CorsConfig config = restConfig.getCorsOrDefault(); return CorsMeta.builder() .allowedOrigins(config.getAllowedOrigins()) .allowedMethods(config.getAllowedMethods()) @@ -43,10 +36,6 @@ public static CorsMeta getGlobalCorsMeta(FrameworkModel frameworkModel) { .build(); } - private static String[] getValues(Configuration config, String key) { - return StringUtils.tokenize(config.getString(key), ','); - } - public static String formatOrigin(String value) { value = value.trim(); int last = value.length() - 1; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/filter/RestExtensionExecutionFilter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/filter/RestExtensionExecutionFilter.java index 66f53fa94bb..a1851fe0a48 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/filter/RestExtensionExecutionFilter.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/filter/RestExtensionExecutionFilter.java @@ -48,6 +48,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; +import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; @@ -143,13 +144,13 @@ protected void onError( private RestFilter[] matchFilters(RestFilter[] filters, String path) { int len = filters.length; BitSet bitSet = new BitSet(len); - out: for (int i = 0; i < len; i++) { RestFilter filter = filters[i]; String[] patterns = filter.getPatterns(); if (ArrayUtils.isEmpty(patterns)) { continue; } + RadixTree filterTree = filterTreeCache.computeIfAbsent(filter, f -> { RadixTree tree = new RadixTree<>(); for (String pattern : patterns) { @@ -166,16 +167,15 @@ private RestFilter[] matchFilters(RestFilter[] filters, String path) { List> matches = filterTree.match(path); int size = matches.size(); - if (size == 0) { - bitSet.set(i); - continue; - } - for (int j = 0; j < size; j++) { - if (!matches.get(j).getValue()) { - bitSet.set(i); - continue out; + if (size > 0) { + if (size > 1) { + Collections.sort(matches); + } + if (matches.get(0).getValue()) { + continue; } } + bitSet.set(i); } if (bitSet.isEmpty()) { return filters; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java index acc27fafee5..efa3b7ca05a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java @@ -16,8 +16,8 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.mapping; -import org.apache.dubbo.common.config.Configuration; -import org.apache.dubbo.common.config.ConfigurationUtils; +import org.apache.dubbo.common.constants.CommonConstants; +import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpUtils; import org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory; @@ -25,26 +25,23 @@ import org.apache.dubbo.remoting.http12.message.codec.CodecUtils; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HandlerMeta; import java.util.HashMap; import java.util.List; import java.util.Map; -import static org.apache.dubbo.config.nested.RestConfig.DEFAULT_FORMAT_PARAMETER_NAME; - public class ContentNegotiator { - private final FrameworkModel frameworkModel; private final CodecUtils codecUtils; private Map extensionMapping; private String parameterName; public ContentNegotiator(FrameworkModel frameworkModel) { - this.frameworkModel = frameworkModel; - codecUtils = frameworkModel.getBeanFactory().getOrRegisterBean(CodecUtils.class); + codecUtils = frameworkModel.getOrRegisterBean(CodecUtils.class); } - public String negotiate(HttpRequest request) { + public String negotiate(HttpRequest request, HandlerMeta meta) { String mediaType; // 1. find mediaType by producible @@ -60,11 +57,19 @@ public String negotiate(HttpRequest request) { // 2. find mediaType by accept header List accepts = HttpUtils.parseAccept(request.accept()); + String preferMediaType = null; + boolean hasAll = false; if (accepts != null) { for (int i = 0, size = accepts.size(); i < size; i++) { - mediaType = getSuitableMediaType(accepts.get(i)); - if (mediaType != null) { - return mediaType; + String accept = accepts.get(i); + if (!hasAll && MediaType.ALL.getName().equals(accept)) { + hasAll = true; + } + if (preferMediaType == null) { + mediaType = getSuitableMediaType(accept); + if (mediaType != null) { + preferMediaType = mediaType; + } } } } @@ -78,15 +83,29 @@ public String negotiate(HttpRequest request) { } } - // 5. find mediaType by extension + // 4. find mediaType by extension String path = request.rawPath(); int index = path.lastIndexOf('.'); if (index != -1) { - String extension = path.substring(index + 1); - return getMediaTypeByExtension(extension); + mediaType = getMediaTypeByExtension(path.substring(index + 1)); + if (mediaType != null) { + return mediaType; + } + } + + if (preferMediaType == null) { + return null; } - return null; + // Keep consistent with Spring MVC behavior + if (hasAll && preferMediaType.startsWith("text/")) { + Class responseType = meta.getMethodMetadata().getActualResponseType(); + if (responseType != null && !CharSequence.class.isAssignableFrom(responseType)) { + return MediaType.APPLICATION_JSON.getName(); + } + } + + return preferMediaType; } public boolean supportExtension(String extension) { @@ -118,11 +137,11 @@ private String getSuitableMediaType(String name) { } public String getParameterName() { - String parameterName = this.parameterName; if (parameterName == null) { - Configuration conf = ConfigurationUtils.getGlobalConfiguration(frameworkModel.defaultApplication()); - parameterName = conf.getString(RestConstants.FORMAT_PARAMETER_NAME_KEY, DEFAULT_FORMAT_PARAMETER_NAME); - this.parameterName = parameterName; + parameterName = ConfigManager.getProtocolOrDefault(CommonConstants.TRIPLE) + .getTripleOrDefault() + .getRestOrDefault() + .getFormatParameterNameOrDefault(); } return parameterName; } @@ -148,10 +167,22 @@ private String getMediaTypeByExtension(String extension) { extensionMapping.put("xhtml", MediaType.TEXT_HTML); extensionMapping.put("html", MediaType.TEXT_HTML); extensionMapping.put("htm", MediaType.TEXT_HTML); + extensionMapping.put("proto", new MediaType(MediaType.TEXT, "proto")); for (String ext : new String[] {"txt", "md", "csv", "log", "properties"}) { extensionMapping.put(ext, MediaType.TEXT_PLAIN); } - + for (String ext : new String[] {"jpg", "jpeg", "png", "gif", "bmp", "svg", "webp", "tiff", "ico"}) { + extensionMapping.put(ext, new MediaType("image", ext)); + } + for (String ext : new String[] {"zip", "gz", "7z", "tar", "rar"}) { + extensionMapping.put(ext, MediaType.APPLICATION_OCTET_STREAM); + } + for (String ext : new String[] {"xls", "xlsx", "doc", "docx", "ppt", "pptx", "pdf"}) { + extensionMapping.put(ext, MediaType.APPLICATION_OCTET_STREAM); + } + for (String ext : new String[] {"mp3", "m4a", "mp4", "avi", "flv"}) { + extensionMapping.put(ext, MediaType.APPLICATION_OCTET_STREAM); + } this.extensionMapping = extensionMapping; } MediaType mediaType = extensionMapping.get(extension); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java index f219b854038..ee38269b505 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java @@ -22,7 +22,9 @@ import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.config.nested.RestConfig; import org.apache.dubbo.remoting.http12.HttpRequest; +import org.apache.dubbo.remoting.http12.exception.HttpStatusException; import org.apache.dubbo.remoting.http12.message.MethodMetadata; +import org.apache.dubbo.remoting.http12.rest.OpenAPIService; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.model.MethodDescriptor; @@ -30,6 +32,7 @@ import org.apache.dubbo.rpc.model.ReflectionServiceDescriptor; import org.apache.dubbo.rpc.model.ServiceDescriptor; import org.apache.dubbo.rpc.protocol.tri.DescriptorUtils; +import org.apache.dubbo.rpc.protocol.tri.TripleProtocol; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; import org.apache.dubbo.rpc.protocol.tri.rest.RestMappingException; @@ -45,6 +48,9 @@ import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Collection; +import java.util.IdentityHashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; @@ -57,24 +63,31 @@ public final class DefaultRequestMappingRegistry implements RequestMappingRegist private static final FluentLogger LOGGER = FluentLogger.of(DefaultRequestMappingRegistry.class); private final FrameworkModel frameworkModel; - private final ContentNegotiator contentNegotiator; private final ReadWriteLock lock = new ReentrantReadWriteLock(); private final AtomicBoolean initialized = new AtomicBoolean(); - private RestConfig restConfig; + private ContentNegotiator contentNegotiator; + private OpenAPIService openAPIService; private List resolvers; + private RestConfig restConfig; private RadixTree tree; public DefaultRequestMappingRegistry(FrameworkModel frameworkModel) { this.frameworkModel = frameworkModel; - contentNegotiator = frameworkModel.getBeanFactory().getOrRegisterBean(ContentNegotiator.class); } private void init(Invoker invoker) { + contentNegotiator = frameworkModel.getOrRegisterBean(ContentNegotiator.class); + if (TripleProtocol.OPENAPI_ENABLED) { + openAPIService = frameworkModel.getBean(OpenAPIService.class); + } + resolvers = frameworkModel.getActivateExtensions(RequestMappingResolver.class); restConfig = ConfigManager.getProtocolOrDefault(invoker.getUrl()) .getTripleOrDefault() .getRestOrDefault(); - resolvers = frameworkModel.getActivateExtensions(RequestMappingResolver.class); + for (RequestMappingResolver resolver : resolvers) { + resolver.setRestConfig(restConfig); + } tree = new RadixTree<>(restConfig.getCaseSensitiveMatchOrDefault()); } @@ -122,7 +135,7 @@ public void register(Invoker invoker) { return; } RequestMapping methodMapping = resolver.resolve(methodMeta); - if (methodMapping == null) { + if (methodMapping == null || methodMapping.getPathCondition() == null) { return; } if (md == null) { @@ -142,6 +155,7 @@ public void register(Invoker invoker) { }); } }); + onMappingChanged(); LOGGER.info( "Registered {} rest mappings for service [{}] at url [{}] in {}ms", counter, @@ -153,17 +167,15 @@ public void register(Invoker invoker) { private void register0(RequestMapping mapping, HandlerMeta handler, AtomicInteger counter) { lock.writeLock().lock(); try { - Registration registration = new Registration(); - registration.mapping = mapping; - registration.meta = handler; + Registration registration = new Registration(mapping, handler); for (PathExpression path : mapping.getPathCondition().getExpressions()) { Registration exists = tree.addPath(path, registration); if (exists == null) { + counter.incrementAndGet(); if (LOGGER.isDebugEnabled()) { String msg = "Register rest mapping: '{}' -> mapping={}, method={}"; LOGGER.debug(msg, path, mapping, handler.getMethod()); } - counter.incrementAndGet(); } else if (LOGGER.isWarnEnabled()) { LOGGER.internalWarn(Messages.DUPLICATE_MAPPING.format(path, mapping, handler.getMethod(), exists)); } @@ -178,9 +190,11 @@ public void unregister(Invoker invoker) { if (tree == null) { return; } + lock.writeLock().lock(); try { - tree.remove(mapping -> mapping.meta.getInvoker() == invoker); + tree.remove(r -> r.getMeta().getInvoker() == invoker); + onMappingChanged(); } finally { lock.writeLock().unlock(); } @@ -191,6 +205,7 @@ public void destroy() { if (tree == null) { return; } + lock.writeLock().lock(); try { tree.clear(); @@ -200,20 +215,24 @@ public void destroy() { } public HandlerMeta lookup(HttpRequest request) { + if (tree == null) { + return null; + } + String stringPath = PathUtils.normalize(request.uri()); request.setAttribute(RestConstants.PATH_ATTRIBUTE, stringPath); KeyString path = new KeyString(stringPath, restConfig.getCaseSensitiveMatchOrDefault()); List candidates = new ArrayList<>(); - tryMatch(request, path, candidates); + List partialMatches = new LinkedList<>(); + tryMatch(request, path, candidates, partialMatches); if (candidates.isEmpty()) { int end = path.length(); - if (restConfig.getTrailingSlashMatchOrDefault()) { + if (end > 1 && restConfig.getTrailingSlashMatchOrDefault()) { if (path.charAt(end - 1) == '/') { - end--; - tryMatch(request, path.subSequence(0, end), candidates); + tryMatch(request, path.subSequence(0, --end), candidates, partialMatches); } } @@ -225,7 +244,7 @@ public HandlerMeta lookup(HttpRequest request) { } if (ch == '.' && restConfig.getSuffixPatternMatchOrDefault()) { if (contentNegotiator.supportExtension(path.toString(i + 1, end))) { - tryMatch(request, path.subSequence(0, i), candidates); + tryMatch(request, path.subSequence(0, i), candidates, partialMatches); if (!candidates.isEmpty()) { break; } @@ -234,7 +253,7 @@ public HandlerMeta lookup(HttpRequest request) { } if (ch == '~') { request.setAttribute(RestConstants.SIG_ATTRIBUTE, path.toString(i + 1, end)); - tryMatch(request, path.subSequence(0, i), candidates); + tryMatch(request, path.subSequence(0, i), candidates, partialMatches); if (!candidates.isEmpty()) { break; } @@ -245,6 +264,7 @@ public HandlerMeta lookup(HttpRequest request) { int size = candidates.size(); if (size == 0) { + handleNoMatch(request, partialMatches); return null; } if (size > 1) { @@ -289,7 +309,8 @@ public HandlerMeta lookup(HttpRequest request) { return handler; } - private void tryMatch(HttpRequest request, KeyString path, List candidates) { + private void tryMatch( + HttpRequest request, KeyString path, List candidates, List partialMatches) { List> matches = new ArrayList<>(); lock.readLock().lock(); @@ -305,20 +326,65 @@ private void tryMatch(HttpRequest request, KeyString path, List candi } for (int i = 0; i < size; i++) { Match match = matches.get(i); - RequestMapping mapping = match.getValue().mapping.match(request, match.getExpression()); + RequestMapping mapping = match.getValue().getMapping().match(request, match.getExpression()); if (mapping != null) { Candidate candidate = new Candidate(); candidate.mapping = mapping; - candidate.meta = match.getValue().meta; + candidate.meta = match.getValue().getMeta(); candidate.expression = match.getExpression(); candidate.variableMap = match.getVariableMap(); candidates.add(candidate); } } + if (candidates.isEmpty()) { + for (int i = 0; i < size; i++) { + partialMatches.add(matches.get(i).getValue().getMapping()); + } + } + } + + private void handleNoMatch(HttpRequest request, List partialMatches) { + if (partialMatches.isEmpty()) { + return; + } + boolean methodsMismatch = true; + boolean consumesMismatch = true; + boolean producesMismatch = true; + boolean paramsMismatch = true; + for (RequestMapping mapping : partialMatches) { + if (methodsMismatch) { + methodsMismatch = !mapping.matchMethod(request.method()); + } + if (consumesMismatch) { + consumesMismatch = !mapping.matchConsumes(request); + } + if (producesMismatch) { + producesMismatch = !mapping.matchProduces(request); + } + if (paramsMismatch) { + paramsMismatch = !mapping.matchParams(request); + } + } + if (methodsMismatch) { + throw new HttpStatusException(405, "Request method '" + request.method() + "' not supported"); + } + if (consumesMismatch) { + throw new HttpStatusException(415, "Content type '" + request.contentType() + "' not supported"); + } + if (producesMismatch) { + throw new HttpStatusException(406, "Could not find acceptable representation"); + } + if (paramsMismatch) { + throw new HttpStatusException(400, "Unsatisfied query parameter conditions"); + } } @Override public boolean exists(String stringPath, String method) { + if (tree == null) { + return false; + } + KeyString path = new KeyString(stringPath, restConfig.getCaseSensitiveMatchOrDefault()); if (tryExists(path, method)) { return true; @@ -355,6 +421,18 @@ public boolean exists(String stringPath, String method) { return false; } + @Override + public Collection getRegistrations() { + lock.readLock().lock(); + try { + Map registrations = new IdentityHashMap<>(); + tree.walk((expr, registration) -> registrations.put(registration, Boolean.TRUE)); + return registrations.keySet(); + } finally { + lock.readLock().unlock(); + } + } + private boolean tryExists(KeyString path, String method) { List> matches = new ArrayList<>(); lock.readLock().lock(); @@ -364,37 +442,16 @@ private boolean tryExists(KeyString path, String method) { lock.readLock().unlock(); } for (int i = 0, size = matches.size(); i < size; i++) { - if (matches.get(i).getValue().mapping.matchMethod(method)) { + if (matches.get(i).getValue().getMapping().matchMethod(method)) { return true; } } return false; } - private static final class Registration { - - RequestMapping mapping; - HandlerMeta meta; - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || obj.getClass() != Registration.class) { - return false; - } - return mapping.equals(((Registration) obj).mapping); - } - - @Override - public int hashCode() { - return mapping.hashCode(); - } - - @Override - public String toString() { - return "Registration{mapping=" + mapping + ", method=" + meta.getMethod() + '}'; + private void onMappingChanged() { + if (openAPIService != null) { + openAPIService.refresh(); } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java index 8e0b1ca238d..786f29ded91 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java @@ -31,6 +31,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.function.BiConsumer; import java.util.function.Predicate; /** @@ -42,14 +43,24 @@ public final class RadixTree { private final Map>> directPathMap = new HashMap<>(); private final Node root = new Node<>(); + private final char separator; private final boolean caseSensitive; - public RadixTree(boolean caseSensitive) { + public RadixTree(boolean caseSensitive, char separator) { this.caseSensitive = caseSensitive; + this.separator = separator; + } + + public RadixTree(boolean caseSensitive) { + this(caseSensitive, '/'); + } + + public RadixTree(char separator) { + this(true, separator); } public RadixTree() { - caseSensitive = true; + this(true, '/'); } public T addPath(PathExpression path, T value) { @@ -85,7 +96,24 @@ public T addPath(PathExpression path, T value) { } public T addPath(String path, T value) { - return addPath(PathExpression.parse(PathUtils.normalize(path)), value); + if (path == null) { + return value; + } + if (separator == '/') { + path = PathUtils.normalize(path); + } else { + path = path.replace(separator, '/'); + if (path.isEmpty() || path.charAt(0) != '/') { + path = '/' + path; + } + } + return addPath(PathExpression.parse(path), value); + } + + public void addPath(T value, String... paths) { + for (String path : paths) { + addPath(path, value); + } } private Node getChild(Node current, PathSegment segment) { @@ -136,6 +164,29 @@ private void removeRecursive(Node current, Predicate tester) { } } + public void walk(BiConsumer consumer) { + for (List> matches : directPathMap.values()) { + for (Match match : matches) { + consumer.accept(match.getExpression(), match.getValue()); + } + } + walkRecursive(root, consumer); + } + + private void walkRecursive(Node root, BiConsumer consumer) { + for (Pair pair : root.values) { + consumer.accept(pair.getLeft(), pair.getRight()); + } + + for (Node node : root.children.values()) { + walkRecursive(node, consumer); + } + + for (Node node : root.fuzzyChildren.values()) { + walkRecursive(node, consumer); + } + } + /** * Ensure that the path is normalized using {@link PathUtils#normalize(String)} before matching. */ @@ -179,20 +230,50 @@ public List> match(String path) { return match(new KeyString(path, caseSensitive)); } + public List> matchRelaxed(String path) { + KeyString keyPath = new KeyString(path, caseSensitive); + List> matches = new ArrayList<>(); + match(keyPath, matches); + if (!matches.isEmpty()) { + return matches; + } + + int end = path.length(); + if (end > 1 && path.charAt(end - 1) == '/') { + match(keyPath.subSequence(0, --end), matches); + if (!matches.isEmpty()) { + return matches; + } + } + + for (int i = end - 1; i >= 0; i--) { + char ch = path.charAt(i); + if (ch == '/') { + break; + } + if (ch == '.') { + match(keyPath.subSequence(0, i), matches); + if (!matches.isEmpty()) { + return matches; + } + } + } + + return matches; + } + private void matchRecursive( Node current, KeyString path, int start, Map variableMap, List> matches) { int end = -2; if (!current.children.isEmpty()) { - end = path.indexOf('/', start); - Node node = current.children.get(path.subSequence(start, end)); - if (node != null) { + end = path.indexOf(separator, start); + Node child = current.children.get(path.subSequence(start, end)); + if (child != null) { if (end == -1) { - if (node.isLeaf()) { - addMatch(node, variableMap, matches); - } - return; + addMatch(child, variableMap, matches); + } else { + matchRecursive(child, path, end + 1, variableMap, matches); } - matchRecursive(node, path, end + 1, variableMap, matches); } } @@ -200,7 +281,7 @@ private void matchRecursive( return; } if (end == -2) { - end = path.indexOf('/', start); + end = path.indexOf(separator, start); } Map workVariableMap = new LinkedHashMap<>(); for (Map.Entry> entry : current.fuzzyChildren.entrySet()) { @@ -212,9 +293,7 @@ private void matchRecursive( addMatch(child, workVariableMap, matches); } else { if (end == -1) { - if (child.isLeaf()) { - addMatch(child, workVariableMap, matches); - } + addMatch(child, workVariableMap, matches); } else { matchRecursive(child, path, end + 1, workVariableMap, matches); } @@ -228,6 +307,17 @@ private void matchRecursive( private static void addMatch(Node node, Map variableMap, List> matches) { List> values = node.values; + if (values.isEmpty()) { + if (node.fuzzyChildren.isEmpty()) { + return; + } + for (Entry> entry : node.fuzzyChildren.entrySet()) { + if (entry.getKey().getType() == Type.WILDCARD_TAIL) { + addMatch(entry.getValue(), variableMap, matches); + } + } + return; + } variableMap = variableMap.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(variableMap); for (int i = 0, size = values.size(); i < size; i++) { Pair pair = values.get(i); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/Registration.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/Registration.java new file mode 100644 index 00000000000..f5c993a4542 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/Registration.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.dubbo.rpc.protocol.tri.rest.mapping; + +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HandlerMeta; + +public final class Registration { + + private final RequestMapping mapping; + private final HandlerMeta meta; + + public Registration(RequestMapping mapping, HandlerMeta meta) { + this.mapping = mapping; + this.meta = meta; + } + + public RequestMapping getMapping() { + return mapping; + } + + public HandlerMeta getMeta() { + return meta; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || obj.getClass() != Registration.class) { + return false; + } + return mapping.equals(((Registration) obj).mapping); + } + + @Override + public int hashCode() { + return mapping.hashCode(); + } + + @Override + public String toString() { + return "Registration{mapping=" + mapping + ", method=" + meta.getMethod() + '}'; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java index 1ea35e0e82a..feef0738e84 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java @@ -119,6 +119,18 @@ public boolean matchMethod(String method) { return methodsCondition == null || methodsCondition.getMethods().contains(method); } + public boolean matchParams(HttpRequest request) { + return paramsCondition == null || paramsCondition.match(request) != null; + } + + public boolean matchConsumes(HttpRequest request) { + return consumesCondition == null || consumesCondition.match(request) != null; + } + + public boolean matchProduces(HttpRequest request) { + return producesCondition == null || producesCondition.match(request) != null; + } + @Override public RequestMapping match(HttpRequest request) { return doMatch(request, null); @@ -208,6 +220,18 @@ public MethodsCondition getMethodsCondition() { return methodsCondition; } + public ParamsCondition getParamsCondition() { + return paramsCondition; + } + + public HeadersCondition getHeadersCondition() { + return headersCondition; + } + + public ConsumesCondition getConsumesCondition() { + return consumesCondition; + } + public ProducesCondition getProducesCondition() { return producesCondition; } @@ -457,7 +481,7 @@ public RequestMapping build() { isEmpty(consumes) ? null : new ConsumesCondition(consumes), isEmpty(produces) ? null : new ProducesCondition(produces), customCondition == null ? null : ConditionWrapper.wrap(customCondition), - cors == null ? null : cors, + cors == null || cors.isEmpty() ? null : cors, responseStatus == null ? null : new ResponseMeta(responseStatus, responseReason)); } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java index 444854c5e78..b27036b1686 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java @@ -20,6 +20,8 @@ import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HandlerMeta; +import java.util.Collection; + /** * RequestMappingRegistry used for registering and unregistering rest request mappings. */ @@ -33,5 +35,7 @@ public interface RequestMappingRegistry { boolean exists(String path, String method); + Collection getRegistrations(); + void destroy(); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingResolver.java index 803792f1a4d..25e34620b0b 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingResolver.java @@ -18,6 +18,7 @@ import org.apache.dubbo.common.extension.ExtensionScope; import org.apache.dubbo.common.extension.SPI; +import org.apache.dubbo.config.nested.RestConfig; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit; @@ -27,6 +28,8 @@ public interface RequestMappingResolver { RestToolKit getRestToolKit(); + default void setRestConfig(RestConfig restConfig) {} + default boolean accept(ServiceMeta serviceMeta) { return true; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RestRequestHandlerMapping.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RestRequestHandlerMapping.java index 73aaffc2f97..2057d8e3988 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RestRequestHandlerMapping.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RestRequestHandlerMapping.java @@ -51,7 +51,6 @@ public final class RestRequestHandlerMapping implements RequestHandlerMapping { private static final Logger LOGGER = LoggerFactory.getLogger(RestRequestHandlerMapping.class); - private final FrameworkModel frameworkModel; private final RequestMappingRegistry requestMappingRegistry; private final ArgumentResolver argumentResolver; private final TypeConverter typeConverter; @@ -59,7 +58,6 @@ public final class RestRequestHandlerMapping implements RequestHandlerMapping { private final CodecUtils codecUtils; public RestRequestHandlerMapping(FrameworkModel frameworkModel) { - this.frameworkModel = frameworkModel; ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory(); requestMappingRegistry = beanFactory.getOrRegisterBean(DefaultRequestMappingRegistry.class); argumentResolver = beanFactory.getOrRegisterBean(CompositeArgumentResolver.class); @@ -89,7 +87,7 @@ public RequestHandler getRequestHandler(URL url, HttpRequest request, HttpRespon } String requestMediaType = request.mediaType(); - String responseMediaType = contentNegotiator.negotiate(request); + String responseMediaType = contentNegotiator.negotiate(request, meta); if (responseMediaType != null) { response.setContentType(responseMediaType); } else { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ConsumesCondition.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ConsumesCondition.java index 181d4c4a1c6..a19030db7fd 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ConsumesCondition.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ConsumesCondition.java @@ -18,6 +18,7 @@ import org.apache.dubbo.remoting.http12.HttpHeaderNames; import org.apache.dubbo.remoting.http12.HttpRequest; +import org.apache.dubbo.remoting.http12.message.MediaType; import java.util.ArrayList; import java.util.Collections; @@ -113,6 +114,10 @@ public int compareTo(ConsumesCondition other, HttpRequest request) { return expressions.get(0).compareTo(other.expressions.get(0)); } + public List getMediaTypes() { + return MediaTypeExpression.toMediaTypes(expressions); + } + @Override public int hashCode() { return expressions.hashCode(); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/MediaTypeExpression.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/MediaTypeExpression.java index 9edb4c71cb2..f4661295a08 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/MediaTypeExpression.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/MediaTypeExpression.java @@ -20,6 +20,7 @@ import org.apache.dubbo.remoting.http12.HttpUtils; import org.apache.dubbo.remoting.http12.message.MediaType; +import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -66,6 +67,16 @@ public MediaTypeExpression(String type, String subType) { negated = false; } + public static List toMediaTypes(List expressions) { + int size = expressions.size(); + List mediaTypes = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + MediaTypeExpression expr = expressions.get(i); + mediaTypes.add(new MediaType(expr.getType(), expr.getSubType())); + } + return mediaTypes; + } + public static MediaTypeExpression parse(String expr) { boolean negated; if (expr.indexOf('!') == 0) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathCondition.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathCondition.java index 5291c504a72..ab1e7147746 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathCondition.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathCondition.java @@ -105,7 +105,9 @@ public PathCondition match(HttpRequest request) { } } if (matches != null) { - Collections.sort(matches); + if (matches.size() > 1) { + Collections.sort(matches); + } Set result = CollectionUtils.newLinkedHashSet(matches.size()); for (int i = 0, size = matches.size(); i < size; i++) { result.add(matches.get(i).getPath()); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpression.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpression.java index 06b48d4f09b..183b718b423 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpression.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpression.java @@ -23,6 +23,7 @@ import java.util.Collections; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; public final class PathExpression implements Comparable { @@ -103,7 +104,7 @@ public int compareTo(PathExpression other) { return result; } } - return otherSize - size; + return size - otherSize; } @Override @@ -127,18 +128,38 @@ public String toString() { if (isDirect()) { return path; } - StringBuilder sb = new StringBuilder(32); + StringBuilder sb = new StringBuilder(path.length()); + int varIndex = 1; for (PathSegment segment : segments) { sb.append('/'); - String value = segment.getValue(); - if (segment.getType() == Type.VARIABLE) { - if (value.isEmpty()) { - sb.append('*'); - } else { - sb.append('{').append(value).append('}'); - } - } else { - sb.append(value); + switch (segment.getType()) { + case LITERAL: + sb.append(segment.getValue()); + break; + case WILDCARD_TAIL: + List variables = segment.getVariables(); + if (variables == null) { + sb.append("{path}"); + } else { + sb.append('{').append(variables.get(0)).append('}'); + } + break; + case VARIABLE: + sb.append('{'); + String value = segment.getValue(); + if (value.isEmpty()) { + sb.append("var").append(varIndex++); + } else { + sb.append(value); + } + sb.append('}'); + break; + case PATTERN: + case PATTERN_MULTI: + sb.append('{').append("var").append(varIndex++).append('}'); + break; + default: + break; } } return sb.toString(); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathSegment.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathSegment.java index 44c50eb852b..e19dbbaf12d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathSegment.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathSegment.java @@ -193,9 +193,9 @@ public int compareTo(PathSegment other) { return comparison; } } - int size = variables == null ? 0 : variables.size(); - int otherSize = other.variables == null ? 0 : other.variables.size(); - return otherSize - size; + int size = variables == null ? 99 : variables.size(); + int otherSize = other.variables == null ? 99 : other.variables.size(); + return size - otherSize; } public enum Type { @@ -212,18 +212,18 @@ public enum Type { LITERAL(1), /** * A wildcard segment. - * E.g.: 't?st*uv' and '/foo/*/bar' + * E.g.: 't?st*uv' */ WILDCARD, /** * A wildcard matching suffix. * Transient type used for parsing, will not be present in the PathExpression - * E.g.: '/foo/**' and '/**' and '/{*bar}' + * E.g.: '/foo/**' or '/**' or '/{*bar}' */ WILDCARD_TAIL, /** * A template variable segment. - * E.g.: '{foo}' + * E.g.: '{foo}' or '/foo/*/bar' */ VARIABLE(10), /** diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ProducesCondition.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ProducesCondition.java index 0f336d1405f..f0f5aed4b3a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ProducesCondition.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ProducesCondition.java @@ -164,14 +164,7 @@ public int compareTo(ProducesCondition other, HttpRequest request) { } public List getMediaTypes() { - List expressions = this.expressions; - int size = expressions.size(); - List mediaTypes = new ArrayList<>(size); - for (int i = 0; i < size; i++) { - MediaTypeExpression expr = expressions.get(i); - mediaTypes.add(new MediaType(expr.getType(), expr.getSubType())); - } - return mediaTypes; + return MediaTypeExpression.toMediaTypes(expressions); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/AnnotationMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/AnnotationMeta.java index 8919222c911..e1505ec5631 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/AnnotationMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/AnnotationMeta.java @@ -17,6 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta; import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit; import java.lang.annotation.Annotation; @@ -174,6 +175,14 @@ attributeName, getAnnotationType().getName(), value), if (expectedType == String.class) { return (T) value.toString(); } + if (expectedType == Boolean.class) { + Boolean b = StringUtils.toBoolean(value.toString()); + return (T) (b == null ? Boolean.FALSE : b); + } + if (expectedType == Number.class) { + String str = value.toString(); + return str.indexOf('.') > -1 ? (T) Double.valueOf(str) : (T) Long.valueOf(str); + } if (expectedType.isArray()) { Class expectedComponentType = expectedType.getComponentType(); if (expectedComponentType.isInstance(value)) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/AnnotationSupport.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/AnnotationSupport.java index 776b8ec93d7..207f4244206 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/AnnotationSupport.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/AnnotationSupport.java @@ -17,7 +17,6 @@ package org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta; import org.apache.dubbo.common.utils.CollectionUtils; -import org.apache.dubbo.common.utils.Pair; import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit; import java.lang.annotation.Annotation; @@ -32,12 +31,12 @@ public abstract class AnnotationSupport { private static final AnnotationMeta[] EMPTY = new AnnotationMeta[0]; - private static final Integer GET_KEY = 1; - private static final Integer GET_MERGED_KEY = 2; - private static final Integer FIND_KEY = 3; - private static final Integer FIND_MERGED_KEY = 4; + private static final int GET_KEY = 1; + private static final int GET_MERGED_KEY = 2; + private static final int FIND_KEY = 3; + private static final int FIND_MERGED_KEY = 4; - private final Map, Optional> cache = CollectionUtils.newConcurrentHashMap(); + private final Map> cache = CollectionUtils.newConcurrentHashMap(); private final Map arrayCache = CollectionUtils.newConcurrentHashMap(); private final RestToolKit toolKit; @@ -72,7 +71,7 @@ public final Annotation[] getRawAnnotations() { } public final AnnotationMeta getAnnotation(Class annotationType) { - return cache.computeIfAbsent(Pair.of(annotationType, GET_KEY), k -> { + return cache.computeIfAbsent(new Key(annotationType, GET_KEY), k -> { AnnotatedElement element = getAnnotatedElement(); Annotation annotation = element.getAnnotation(annotationType); if (annotation != null) { @@ -96,7 +95,7 @@ public final boolean isAnnotated(AnnotationEnum annotationEnum) { } public final AnnotationMeta getMergedAnnotation(Class annotationType) { - return cache.computeIfAbsent(Pair.of(annotationType, GET_MERGED_KEY), k -> { + return cache.computeIfAbsent(new Key(annotationType, GET_MERGED_KEY), k -> { AnnotatedElement element = getAnnotatedElement(); Annotation[] annotations = element.getAnnotations(); for (Annotation annotation : annotations) { @@ -144,7 +143,7 @@ public final AnnotationMeta[] findAnnotations() { } public final AnnotationMeta findAnnotation(Class annotationType) { - return cache.computeIfAbsent(Pair.of(annotationType, FIND_KEY), k -> { + return cache.computeIfAbsent(new Key(annotationType, FIND_KEY), k -> { List elements = getAnnotatedElements(); for (int i = 0, size = elements.size(); i < size; i++) { AnnotatedElement element = elements.get(i); @@ -171,7 +170,7 @@ public final boolean isHierarchyAnnotated(AnnotationEnum annotationEnum) { } public final AnnotationMeta findMergedAnnotation(Class annotationType) { - return cache.computeIfAbsent(Pair.of(annotationType, FIND_MERGED_KEY), k -> { + return cache.computeIfAbsent(new Key(annotationType, FIND_MERGED_KEY), k -> { List elements = getAnnotatedElements(); for (int i = 0, size = elements.size(); i < size; i++) { AnnotatedElement element = elements.get(i); @@ -208,9 +207,32 @@ public final RestToolKit getToolKit() { return toolKit; } - protected List getAnnotatedElements() { + public List getAnnotatedElements() { return Collections.singletonList(getAnnotatedElement()); } + private static final class Key { + + private final Class annotationType; + private final int type; + + Key(Class annotationType, int type) { + this.annotationType = annotationType; + this.type = type; + } + + @Override + public int hashCode() { + return (annotationType.hashCode() << 2) + type; + } + + @SuppressWarnings({"EqualsWhichDoesntCheckParameterClass", "EqualsDoesntCheckParameterClass"}) + @Override + public boolean equals(Object obj) { + Key other = (Key) obj; + return annotationType == other.annotationType && type == other.type; + } + } + protected abstract AnnotatedElement getAnnotatedElement(); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java index 5c827876d16..60635c0b3f1 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta; +import org.apache.dubbo.common.utils.ClassUtils; import org.apache.dubbo.remoting.http12.rest.Param; import org.apache.dubbo.rpc.protocol.tri.ExceptionUtils; import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit; @@ -31,47 +32,88 @@ import java.lang.reflect.Modifier; import java.lang.reflect.Parameter; import java.lang.reflect.Type; +import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; -public final class BeanMeta { +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.Message; - private final Map fields = new LinkedHashMap<>(); - private final Map methods = new LinkedHashMap<>(); - private final ConstructorMeta constructor; +public final class BeanMeta extends ParameterMeta { - public BeanMeta(RestToolKit toolKit, String prefix, Class type) { - constructor = resolveConstructor(toolKit, prefix, type); - resolveFieldAndMethod(toolKit, prefix, type); + private static final boolean HAS_PB = ClassUtils.hasProtobuf(); + + private final Class type; + private final boolean flatten; + private ConstructorMeta constructor; + private Map propertyMap; + + public BeanMeta(RestToolKit toolKit, String prefix, Class type, boolean flatten) { + super(toolKit, prefix, null); + this.type = type; + this.flatten = flatten; } - public BeanMeta(RestToolKit toolKit, Class type) { - this(toolKit, null, type); + public BeanMeta(RestToolKit toolKit, Class type, boolean flatten) { + this(toolKit, null, type, flatten); } - public Collection getFields() { - return fields.values(); + public BeanMeta(RestToolKit toolKit, String prefix, Class type) { + this(toolKit, prefix, type, true); } - public FieldMeta getField(String name) { - return fields.get(name); + public BeanMeta(RestToolKit toolKit, Class type) { + this(toolKit, null, type, true); } - public Collection getMethods() { - return methods.values(); + @Override + public Class getType() { + return type; } - public SetMethodMeta getMethod(String name) { - return methods.get(name); + @Override + public Type getGenericType() { + return type; + } + + @Override + protected AnnotatedElement getAnnotatedElement() { + return type; } public ConstructorMeta getConstructor() { + if (constructor == null) { + constructor = resolveConstructor(getToolKit(), getPrefix(), type); + } return constructor; } + public Collection getProperties() { + return getPropertiesMap().values(); + } + + public PropertyMeta getProperty(String name) { + return getPropertiesMap().get(name); + } + + private Map getPropertiesMap() { + Map propertyMap = this.propertyMap; + if (propertyMap == null) { + propertyMap = new LinkedHashMap<>(); + resolvePropertyMap(getToolKit(), getPrefix(), type, flatten, propertyMap); + this.propertyMap = propertyMap; + } + return propertyMap; + } + public Object newInstance() { - return constructor.newInstance(); + return getConstructor().newInstance(); } public static ConstructorMeta resolveConstructor(RestToolKit toolKit, String prefix, Class type) { @@ -91,46 +133,98 @@ public static ConstructorMeta resolveConstructor(RestToolKit toolKit, String pre return new ConstructorMeta(toolKit, prefix, ct); } - private void resolveFieldAndMethod(RestToolKit toolKit, String prefix, Class type) { - if (type == Object.class) { + public static void resolvePropertyMap( + RestToolKit toolKit, String prefix, Class type, boolean flatten, Map propertyMap) { + if (type == null || type == Object.class || TypeUtils.isSystemType(type)) { return; } - for (Field field : type.getDeclaredFields()) { - int modifiers = field.getModifiers(); - if (Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers)) { - continue; - } - if (field.getAnnotations().length == 0) { - continue; + + Set pbFields = null; + if (HAS_PB && Message.class.isAssignableFrom(type)) { + try { + Descriptor descriptor = + (Descriptor) type.getMethod("getDescriptor").invoke(null); + pbFields = descriptor.getFields().stream() + .map(FieldDescriptor::getName) + .collect(Collectors.toSet()); + } catch (Exception ignored) { } - if (!field.isAccessible()) { - field.setAccessible(true); + } + + Set allNames = new LinkedHashSet<>(); + Map fieldMap = new LinkedHashMap<>(); + if (pbFields == null) { + for (Field field : type.getDeclaredFields()) { + if (Modifier.isStatic(field.getModifiers()) + || Modifier.isTransient(field.getModifiers()) + || field.isSynthetic()) { + continue; + } + if (!field.isAccessible()) { + field.setAccessible(true); + } + fieldMap.put(field.getName(), field); + allNames.add(field.getName()); } - FieldMeta fieldMeta = new FieldMeta(toolKit, prefix, field); - fields.put(fieldMeta.getName(), fieldMeta); } + + Map getMethodMap = new LinkedHashMap<>(); + Map setMethodMap = new LinkedHashMap<>(); for (Method method : type.getDeclaredMethods()) { - if (method.getParameterCount() != 1) { - continue; - } int modifiers = method.getModifiers(); if ((modifiers & (Modifier.PUBLIC | Modifier.ABSTRACT | Modifier.STATIC)) == Modifier.PUBLIC) { - Parameter parameter = method.getParameters()[0]; String name = method.getName(); - if (name.length() > 3 && name.startsWith("set")) { - String getMethodName = "get" + name.substring(3); - Method getMethod = null; - try { - getMethod = type.getDeclaredMethod(getMethodName); - } catch (NoSuchMethodException ignored) { + int count = method.getParameterCount(); + if (count == 0) { + Class returnType = method.getReturnType(); + if (returnType == Void.TYPE) { + continue; + } + if (name.length() > 3 && name.startsWith("get")) { + name = toName(name, 3); + if (pbFields == null || pbFields.contains(name)) { + getMethodMap.put(name, method); + allNames.add(name); + } + } else if (name.length() > 2 && name.startsWith("is") && returnType == Boolean.TYPE) { + if (pbFields == null || pbFields.contains(name)) { + name = toName(name, 2); + getMethodMap.put(name, method); + allNames.add(name); + } + } else if (fieldMap.containsKey(name)) { + // For record class + getMethodMap.put(name, method); + allNames.add(name); + } + } else if (count == 1) { + if (name.length() > 3 && name.startsWith("set")) { + name = toName(name, 3); + setMethodMap.put(name, method); + allNames.add(name); } - name = Character.toLowerCase(name.charAt(3)) + name.substring(4); - SetMethodMeta methodMeta = new SetMethodMeta(toolKit, method, getMethod, parameter, prefix, name); - methods.put(methodMeta.getName(), methodMeta); } } } - resolveFieldAndMethod(toolKit, prefix, type.getSuperclass()); + + for (String name : allNames) { + Field field = fieldMap.get(name); + Method getMethod = getMethodMap.get(name); + Method setMethod = setMethodMap.get(name); + int visibility = pbFields == null + ? (setMethod == null ? 0 : 1) << 2 | (getMethod == null ? 0 : 1) << 1 | (field == null ? 0 : 1) + : 0b011; + PropertyMeta meta = new PropertyMeta(toolKit, field, getMethod, setMethod, prefix, name, visibility); + propertyMap.put(meta.getName(), meta); + } + + if (flatten) { + resolvePropertyMap(toolKit, prefix, type.getSuperclass(), true, propertyMap); + } + } + + private static String toName(String name, int index) { + return Character.toLowerCase(name.charAt(index)) + name.substring(index + 1); } public static final class ConstructorMeta { @@ -150,9 +244,14 @@ public ConstructorParameterMeta[] getParameters() { private ConstructorParameterMeta[] initParameters(RestToolKit toolKit, String prefix, Constructor ct) { Parameter[] cps = ct.getParameters(); int len = cps.length; + if (len == 0) { + return new ConstructorParameterMeta[0]; + } + String[] parameterNames = toolKit == null ? null : toolKit.getParameterNames(ct); ConstructorParameterMeta[] parameters = new ConstructorParameterMeta[len]; for (int i = 0; i < len; i++) { - parameters[i] = new ConstructorParameterMeta(toolKit, cps[i], prefix); + String parameterName = parameterNames == null ? null : parameterNames[i]; + parameters[i] = new ConstructorParameterMeta(toolKit, cps[i], prefix, parameterName); } return parameters; } @@ -170,8 +269,8 @@ public static final class ConstructorParameterMeta extends ParameterMeta { private final Parameter parameter; - ConstructorParameterMeta(RestToolKit toolKit, Parameter parameter, String prefix) { - super(toolKit, prefix, parameter.isNamePresent() ? parameter.getName() : null); + ConstructorParameterMeta(RestToolKit toolKit, Parameter parameter, String prefix, String name) { + super(toolKit, prefix, name == null && parameter.isNamePresent() ? parameter.getName() : name); this.parameter = parameter; } @@ -222,12 +321,12 @@ public final String getName() { return name; } - public void setValue(Object bean, Object value) {} - public Object getValue(Object bean) { return null; } + public void setValue(Object bean, Object value) {} + public final NestableParameterMeta getNestedMeta() { return nestedMeta; } @@ -251,104 +350,132 @@ protected final void initNestedMeta() { } } - public static final class FieldMeta extends NestableParameterMeta { + public static final class PropertyMeta extends NestableParameterMeta { private final Field field; + private final Method getMethod; + private final Method setMethod; + private final Parameter parameter; + private final int visibility; - FieldMeta(RestToolKit toolKit, String prefix, Field field) { - super(toolKit, prefix, field.getName()); - this.field = field; + PropertyMeta(RestToolKit toolKit, Field f, Method gm, Method sm, String prefix, String name, int visibility) { + super(toolKit, prefix, name); + this.visibility = visibility; + field = f; + getMethod = gm; + setMethod = sm; + parameter = setMethod == null ? null : setMethod.getParameters()[0]; initNestedMeta(); } - @Override - public Class getType() { - return field.getType(); + public int getVisibility() { + return visibility; } - @Override - public Type getGenericType() { - return field.getGenericType(); - } - - @Override - protected AnnotatedElement getAnnotatedElement() { + public Field getField() { return field; } - public void setValue(Object bean, Object value) { - try { - field.set(bean, value); - } catch (Throwable t) { - throw ExceptionUtils.wrap(t); - } - } - - public Object getValue(Object bean) { - try { - return field.get(bean); - } catch (Throwable t) { - throw ExceptionUtils.wrap(t); - } + public Method getGetMethod() { + return getMethod; } - @Override - public String getDescription() { - return "FieldParameter{" + field + '}'; + public Method getSetMethod() { + return setMethod; } - } - public static final class SetMethodMeta extends NestableParameterMeta { - - private final Method method; - private final Method getMethod; - private final Parameter parameter; - - SetMethodMeta(RestToolKit toolKit, Method m, Method gm, Parameter p, String prefix, String name) { - super(toolKit, prefix, name); - method = m; - getMethod = gm; - parameter = p; - initNestedMeta(); + public Parameter getParameter() { + return parameter; } @Override public Class getType() { - return parameter.getType(); + if (field != null) { + return field.getType(); + } + if (parameter != null) { + return parameter.getType(); + } + return getMethod.getReturnType(); } @Override public Type getGenericType() { - return parameter.getParameterizedType(); + if (field != null) { + return field.getGenericType(); + } + if (parameter != null) { + return parameter.getParameterizedType(); + } + return getMethod.getGenericReturnType(); } @Override protected AnnotatedElement getAnnotatedElement() { - return parameter; + if (field != null) { + return field; + } + if (parameter != null) { + return parameter; + } + return getMethod; } - public void setValue(Object bean, Object value) { - try { - method.invoke(bean, value); - } catch (Throwable t) { - throw ExceptionUtils.wrap(t); + @Override + public List getAnnotatedElements() { + List elements = new ArrayList<>(3); + if (field != null) { + elements.add(field); + } + if (parameter != null) { + elements.add(parameter); } + if (getMethod != null) { + elements.add(getMethod); + } + return elements; } public Object getValue(Object bean) { - if (getMethod == null) { - return null; + if (getMethod != null) { + try { + return getMethod.invoke(bean); + } catch (Throwable t) { + throw ExceptionUtils.wrap(t); + } + } else if (field != null) { + try { + return field.get(bean); + } catch (Throwable t) { + throw ExceptionUtils.wrap(t); + } } - try { - return getMethod.invoke(bean); - } catch (Throwable t) { - throw ExceptionUtils.wrap(t); + return null; + } + + public void setValue(Object bean, Object value) { + if (setMethod != null) { + try { + setMethod.invoke(bean, value); + } catch (Throwable t) { + throw ExceptionUtils.wrap(t); + } + } else if (field != null) { + try { + field.set(bean, value); + } catch (Throwable t) { + throw ExceptionUtils.wrap(t); + } } } @Override public String getDescription() { - return "SetMethodParameter{" + method + '}'; + return "PropertyMeta{" + (field == null ? (parameter == null ? getMethod : parameter) : field) + '}'; + } + + public boolean canSetValue() { + return setMethod != null || field != null; } } @@ -376,7 +503,7 @@ public Type getGenericType() { @Override protected AnnotatedElement getAnnotatedElement() { - return null; + return type; } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodMeta.java index 5e3f7c2eac7..de2328004ea 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodMeta.java @@ -35,6 +35,7 @@ public final class MethodMeta extends AnnotationSupport { private final Method method; private MethodDescriptor methodDescriptor; private ParameterMeta[] parameters; + private ParameterMeta returnParameter; private final ServiceMeta serviceMeta; public MethodMeta(List hierarchy, MethodDescriptor methodDescriptor, ServiceMeta serviceMeta) { @@ -106,6 +107,14 @@ public ParameterMeta[] getParameters() { return parameters; } + public ParameterMeta getReturnParameter() { + ParameterMeta returnParameter = this.returnParameter; + if (returnParameter == null) { + this.returnParameter = returnParameter = new ReturnParameterMeta(getToolKit(), hierarchy, method); + } + return returnParameter; + } + public ServiceMeta getServiceMeta() { return serviceMeta; } @@ -114,12 +123,20 @@ public Class getReturnType() { return method.getReturnType(); } + public Class getActualReturnType() { + return getReturnParameter().getActualType(); + } + public Type getGenericReturnType() { return method.getGenericReturnType(); } + public Type getActualGenericReturnType() { + return getReturnParameter().getActualGenericType(); + } + @Override - protected List getAnnotatedElements() { + public List getAnnotatedElements() { return hierarchy; } @@ -153,7 +170,7 @@ public String toShortString() { return MethodUtils.toShortString(method); } - private static final class StreamParameterMeta extends ParameterMeta { + public static final class StreamParameterMeta extends ParameterMeta { private final Class type; private final Type genericType; @@ -193,8 +210,44 @@ protected AnnotatedElement getAnnotatedElement() { } @Override - protected List getAnnotatedElements() { + public List getAnnotatedElements() { return elements; } } + + public static final class ReturnParameterMeta extends ParameterMeta { + + private final List hierarchy; + private final Method method; + + ReturnParameterMeta(RestToolKit toolKit, List hierarchy, Method method) { + super(toolKit, null); + this.hierarchy = hierarchy; + this.method = method; + } + + public Method getMethod() { + return method; + } + + @Override + public Class getType() { + return method.getReturnType(); + } + + @Override + public Type getGenericType() { + return method.getGenericReturnType(); + } + + @Override + public List getAnnotatedElements() { + return hierarchy; + } + + @Override + protected AnnotatedElement getAnnotatedElement() { + return method; + } + } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodParameterMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodParameterMeta.java index e9b82cf4828..014e6130897 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodParameterMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodParameterMeta.java @@ -79,7 +79,7 @@ protected AnnotatedElement getAnnotatedElement() { } @Override - protected List getAnnotatedElements() { + public List getAnnotatedElements() { return hierarchy; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/NamedValueMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/NamedValueMeta.java index 69a1af9bb98..cbe12e52565 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/NamedValueMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/NamedValueMeta.java @@ -17,6 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta; import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestException; @@ -25,13 +26,16 @@ public class NamedValueMeta { + public static final NamedValueMeta EMPTY = new NamedValueMeta(); + private String name; private final boolean required; private final String defaultValue; + private ParamType paramType; private Class type; private Type genericType; private Class[] nestedTypes; - private ParameterMeta parameterMeta; + private ParameterMeta parameter; public NamedValueMeta(String name, boolean required, String defaultValue) { this.name = name; @@ -39,10 +43,15 @@ public NamedValueMeta(String name, boolean required, String defaultValue) { this.defaultValue = defaultValue; } - public NamedValueMeta(boolean required, String defaultValue) { - name = null; + public NamedValueMeta(String name, boolean required) { + this.name = name; this.required = required; - this.defaultValue = defaultValue; + defaultValue = null; + } + + public NamedValueMeta() { + required = false; + defaultValue = null; } public String name() { @@ -52,8 +61,9 @@ public String name() { return name; } - public void setName(String name) { + public NamedValueMeta setName(String name) { this.name = name; + return this; } public boolean isNameEmpty() { @@ -68,44 +78,57 @@ public String defaultValue() { return defaultValue; } + public ParamType paramType() { + return paramType; + } + + public NamedValueMeta setParamType(ParamType paramType) { + this.paramType = paramType; + return this; + } + public Class type() { return type; } - public void setType(Class type) { + public NamedValueMeta setType(Class type) { this.type = type; + return this; } public Type genericType() { return genericType; } - public void setGenericType(Type genericType) { + public NamedValueMeta setGenericType(Type genericType) { this.genericType = genericType; + return this; } - public Class nestedType() { - return nestedTypes == null ? null : nestedTypes[0]; + public Class[] nestedTypes() { + return nestedTypes; } - public Class nestedType(int index) { - return nestedTypes == null || nestedTypes.length <= index ? null : nestedTypes[index]; + public NamedValueMeta setNestedTypes(Class[] nestedTypes) { + this.nestedTypes = nestedTypes; + return this; } - public Class[] nestedTypes() { - return nestedTypes; + public Class nestedType() { + return nestedTypes == null ? null : nestedTypes[0]; } - public void setNestedTypes(Class[] nestedTypes) { - this.nestedTypes = nestedTypes; + public Class nestedType(int index) { + return nestedTypes == null || nestedTypes.length <= index ? null : nestedTypes[index]; } - public ParameterMeta parameterMeta() { - return parameterMeta; + public ParameterMeta parameter() { + return parameter; } - public void setParameterMeta(ParameterMeta parameterMeta) { - this.parameterMeta = parameterMeta; + public NamedValueMeta setParameter(ParameterMeta parameter) { + this.parameter = parameter; + return this; } @Override @@ -118,6 +141,9 @@ public String toString() { if (defaultValue != null) { sb.append(", defaultValue='").append(defaultValue).append('\''); } + if (paramType != null) { + sb.append(", paramType=").append(paramType); + } if (type != null) { sb.append(", type=").append(type); if (genericType != type) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ParameterMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ParameterMeta.java index 33f02fdb311..d9a46ef2966 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ParameterMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ParameterMeta.java @@ -25,10 +25,8 @@ import javax.annotation.Nullable; -import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Collection; -import java.util.Optional; public abstract class ParameterMeta extends AnnotationSupport { @@ -37,6 +35,8 @@ public abstract class ParameterMeta extends AnnotationSupport { private Boolean simple; private Class actualType; private Type actualGenericType; + private BeanMeta beanMeta; + private NamedValueMeta namedValueMeta; protected ParameterMeta(RestToolKit toolKit, String prefix, String name) { super(toolKit); @@ -83,7 +83,7 @@ public final Class getActualType() { Class type = actualType; if (type == null) { type = getType(); - if (type == Optional.class) { + if (TypeUtils.isWrapperType(type)) { type = TypeUtils.getNestedActualType(getGenericType(), 0); if (type == null) { type = Object.class; @@ -98,8 +98,8 @@ public final Type getActualGenericType() { Type type = actualGenericType; if (type == null) { type = getGenericType(); - if (type instanceof ParameterizedType && ((ParameterizedType) type).getRawType() == Optional.class) { - type = TypeUtils.getNestedGenericType(getGenericType(), 0); + if (TypeUtils.isWrapperType(TypeUtils.getActualType(type))) { + type = TypeUtils.getNestedGenericType(type, 0); if (type == null) { type = Object.class; } @@ -109,10 +109,30 @@ public final Type getActualGenericType() { return type; } + public final BeanMeta getBeanMeta() { + BeanMeta beanMeta = this.beanMeta; + if (beanMeta == null) { + this.beanMeta = beanMeta = new BeanMeta(getToolKit(), getActualType()); + } + return beanMeta; + } + public final Object bind(HttpRequest request, HttpResponse response) { return getToolKit().bind(this, request, response); } + public final NamedValueMeta getNamedValueMeta() { + NamedValueMeta namedValueMeta = this.namedValueMeta; + if (namedValueMeta == null) { + namedValueMeta = getToolKit().getNamedValueMeta(this); + if (namedValueMeta == null) { + namedValueMeta = NamedValueMeta.EMPTY; + } + this.namedValueMeta = namedValueMeta; + } + return namedValueMeta; + } + public int getIndex() { return -1; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ProtoBean.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ProtoBean.java new file mode 100644 index 00000000000..3f9a9d3327d --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ProtoBean.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.dubbo.rpc.protocol.tri.rest.mapping.meta; + +import org.apache.dubbo.common.utils.ClassUtils; + +import java.util.Set; +import java.util.stream.Collectors; + +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.Message; + +final class ProtoBean { + + public static final boolean HAS_PB = ClassUtils.hasProtobuf(); + + public static Set getFields(Class clazz) { + if (HAS_PB && Message.class.isAssignableFrom(clazz)) { + try { + Descriptor descriptor = + (Descriptor) clazz.getMethod("getDescriptor").invoke(null); + return descriptor.getFields().stream() + .map(FieldDescriptor::getName) + .collect(Collectors.toSet()); + } catch (Exception ignored) { + } + } + return null; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ServiceMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ServiceMeta.java index 6c45b202cb6..cbb34bf8460 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ServiceMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ServiceMeta.java @@ -94,7 +94,7 @@ public List getExceptionHandlers() { } @Override - protected List getAnnotatedElements() { + public List getAnnotatedElements() { return hierarchy; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/TypeParameterMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/TypeParameterMeta.java new file mode 100644 index 00000000000..edbf75f196a --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/TypeParameterMeta.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.dubbo.rpc.protocol.tri.rest.mapping.meta; + +import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit; +import org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils; + +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Type; + +public final class TypeParameterMeta extends ParameterMeta { + + private final Type type; + + public TypeParameterMeta(RestToolKit toolKit, Type type) { + super(toolKit, null); + this.type = type; + } + + public TypeParameterMeta(Type type) { + super(null, null); + this.type = type; + } + + @Override + public Class getType() { + return TypeUtils.getActualType(type); + } + + @Override + public Type getGenericType() { + return type; + } + + @Override + protected AnnotatedElement getAnnotatedElement() { + return getActualType(); + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/Annotations.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/Annotations.java index 5a1ef216aa0..3dc74da8f3c 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/Annotations.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/Annotations.java @@ -23,6 +23,9 @@ public enum Annotations implements AnnotationEnum { Mapping, Param, + OpenAPI, + Operation, + Schema, Nonnull("javax.annotation.Nonnull"); private final String className; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRequestMappingResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRequestMappingResolver.java index bddaadefc9a..533d2b155d4 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRequestMappingResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRequestMappingResolver.java @@ -18,6 +18,7 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.nested.RestConfig; import org.apache.dubbo.remoting.http12.rest.Mapping; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.cors.CorsUtils; @@ -36,12 +37,11 @@ @Activate public class BasicRequestMappingResolver implements RequestMappingResolver { - private final FrameworkModel frameworkModel; private final RestToolKit toolKit; + private RestConfig restConfig; private CorsMeta globalCorsMeta; public BasicRequestMappingResolver(FrameworkModel frameworkModel) { - this.frameworkModel = frameworkModel; toolKit = new BasicRestToolKit(frameworkModel); } @@ -50,6 +50,11 @@ public RestToolKit getRestToolKit() { return toolKit; } + @Override + public void setRestConfig(RestConfig restConfig) { + this.restConfig = restConfig; + } + @Override public boolean accept(MethodMeta methodMeta) { AnnotationMeta mapping = methodMeta.findAnnotation(Mapping.class); @@ -77,8 +82,15 @@ public RequestMapping resolve(ServiceMeta serviceMeta) { public RequestMapping resolve(MethodMeta methodMeta) { Method method = methodMeta.getMethod(); AnnotationMeta mapping = methodMeta.findAnnotation(Mapping.class); - if (mapping != null && !mapping.getAnnotation().enabled()) { - return null; + if (mapping != null) { + if (!mapping.getAnnotation().enabled()) { + return null; + } + } else { + Boolean enabled = restConfig.getEnableDefaultMapping(); + if (enabled != null && !enabled) { + return null; + } } Builder builder = builder(mapping); @@ -92,7 +104,7 @@ public RequestMapping resolve(MethodMeta methodMeta) { ServiceMeta serviceMeta = methodMeta.getServiceMeta(); if (globalCorsMeta == null) { - globalCorsMeta = CorsUtils.getGlobalCorsMeta(frameworkModel); + globalCorsMeta = CorsUtils.getGlobalCorsMeta(restConfig); } return builder.name(method.getName()) .service(serviceMeta.getServiceGroup(), serviceMeta.getServiceVersion()) diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRestToolKit.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRestToolKit.java index 8aac208d8bf..edaf5cdd983 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRestToolKit.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRestToolKit.java @@ -29,7 +29,7 @@ final class BasicRestToolKit extends AbstractRestToolKit { public BasicRestToolKit(FrameworkModel frameworkModel) { super(frameworkModel); - binder = new BeanArgumentBinder(frameworkModel); + binder = new BeanArgumentBinder(argumentResolver); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BeanArgumentBinder.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BeanArgumentBinder.java index 93214b2bff2..285e93ef218 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BeanArgumentBinder.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BeanArgumentBinder.java @@ -23,16 +23,14 @@ import org.apache.dubbo.remoting.http12.HttpResponse; import org.apache.dubbo.remoting.http12.rest.Param; import org.apache.dubbo.remoting.http12.rest.ParamType; -import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestException; import org.apache.dubbo.rpc.protocol.tri.rest.argument.CompositeArgumentResolver; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.ConstructorMeta; -import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.FieldMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.NestableParameterMeta; -import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.SetMethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.PropertyMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils; @@ -50,8 +48,8 @@ final class BeanArgumentBinder { private final CompositeArgumentResolver argumentResolver; - public BeanArgumentBinder(FrameworkModel frameworkModel) { - argumentResolver = frameworkModel.getBeanFactory().getOrRegisterBean(CompositeArgumentResolver.class); + public BeanArgumentBinder(CompositeArgumentResolver argumentResolver) { + this.argumentResolver = argumentResolver; } public Object bind(ParameterMeta paramMeta, HttpRequest request, HttpResponse response) { @@ -124,12 +122,8 @@ public Object bind(ParameterMeta paramMeta, HttpRequest request, HttpResponse re current.setValue(argumentResolver.getArgumentConverter().convert(value, current.paramMeta)); } - for (FieldMeta fieldMeta : beanMeta.getFields()) { - resolveParam(fieldMeta, bean, request, response); - } - - for (SetMethodMeta methodMeta : beanMeta.getMethods()) { - resolveParam(methodMeta, bean, request, response); + for (PropertyMeta propertyMeta : beanMeta.getProperties()) { + resolveParam(propertyMeta, bean, request, response); } return bean; @@ -151,7 +145,7 @@ private static BeanMeta getBeanMeta(ParameterMeta paramMeta) { if (paramMeta.isSimple() || Modifier.isAbstract(type.getModifiers())) { return null; } - return CACHE.computeIfAbsent(type, k -> new BeanMeta(paramMeta.getToolKit(), k)); + return CACHE.computeIfAbsent(type, k -> paramMeta.getBeanMeta()); } /** @@ -208,14 +202,9 @@ public Node getChild(String name) { return null; } - NestableParameterMeta methodMeta = beanMeta.getMethod(name); - if (methodMeta != null) { - return createChild(name, methodMeta, v -> methodMeta.setValue(value, v)); - } - - NestableParameterMeta fieldMeta = beanMeta.getField(name); - if (fieldMeta != null) { - return createChild(name, fieldMeta, v -> fieldMeta.setValue(value, v)); + PropertyMeta propertyMeta = beanMeta.getProperty(name); + if (propertyMeta != null) { + return createChild(name, propertyMeta, v -> propertyMeta.setValue(value, v)); } return null; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/FallbackArgumentResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/FallbackArgumentResolver.java index 35c40c881e9..82caf9dfd5a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/FallbackArgumentResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/FallbackArgumentResolver.java @@ -28,6 +28,7 @@ import org.apache.dubbo.rpc.protocol.tri.rest.argument.AbstractArgumentResolver; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta.StreamParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; @@ -60,6 +61,9 @@ protected NamedValueMeta createNamedValueMeta(ParameterMeta param) { } } paramCount = methodMeta.getMethodDescriptor().getRpcType() != RpcType.UNARY ? 1 : paramMetas.length; + } else if (param instanceof StreamParameterMeta) { + paramCount = 1; + noBodyParam = false; } return new FallbackNamedValueMeta(param.isAnnotated(Annotations.Nonnull), noBodyParam, paramCount); } @@ -96,7 +100,7 @@ protected Object doResolveValue(NamedValueMeta meta, boolean single, HttpRequest if (body instanceof List) { List list = (List) body; if (list.size() == fm.paramCount) { - return list.get(meta.parameterMeta().getIndex()); + return list.get(meta.parameter().getIndex()); } } else if (body instanceof Map) { Object value = ((Map) body).get(meta.name()); @@ -112,10 +116,10 @@ protected Object doResolveValue(NamedValueMeta meta, boolean single, HttpRequest return RequestUtils.getParametersMap(request); } String value = request.parameter(meta.name()); - if (meta.parameterMeta().isSimple() || RestUtils.isMaybeJSONObject(value)) { + if (meta.parameter().isSimple() || RestUtils.isMaybeJSONObject(value)) { return value; } - return meta.parameterMeta().bind(request, response); + return meta.parameter().bind(request, response); } return request.parameterValues(meta.name()); @@ -132,7 +136,7 @@ private static final class FallbackNamedValueMeta extends NamedValueMeta { private final int paramCount; FallbackNamedValueMeta(boolean required, boolean noBodyParam, int paramCount) { - super(required, null); + super(null, required); this.noBodyParam = noBodyParam; this.paramCount = paramCount; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/GRequestArgumentResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/GRequestArgumentResolver.java new file mode 100644 index 00000000000..0f0e0e7caef --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/GRequestArgumentResolver.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.dubbo.rpc.protocol.tri.rest.support.basic; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.common.utils.JsonUtils; +import org.apache.dubbo.remoting.http12.HttpRequest; +import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.exception.DecodeException; +import org.apache.dubbo.remoting.http12.message.HttpMessageDecoder; +import org.apache.dubbo.remoting.http12.rest.ParamType; +import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; +import org.apache.dubbo.rpc.protocol.tri.rest.argument.AnnotationBaseArgumentResolver; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; +import org.apache.dubbo.rpc.stub.annotations.GRequest; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.annotation.Annotation; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +@Activate +public class GRequestArgumentResolver implements AnnotationBaseArgumentResolver { + + @Override + public Class accept() { + return GRequest.class; + } + + @Override + public NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta annotation) { + return new NamedValueMeta().setParamType(ParamType.Body); + } + + @Override + public Object resolve( + ParameterMeta parameter, AnnotationMeta annotation, HttpRequest request, HttpResponse response) { + HttpMessageDecoder decoder = request.attribute(RestConstants.BODY_DECODER_ATTRIBUTE); + if (decoder == null) { + return null; + } + + Map value = new HashMap<>(); + Map variableMap = request.attribute(RestConstants.URI_TEMPLATE_VARIABLES_ATTRIBUTE); + if (variableMap != null) { + value.putAll(variableMap); + } + + InputStream is = request.inputStream(); + try { + int available = is.available(); + if (available > 0) { + Object body = decoder.decode(is, Object.class, request.charsetOrDefault()); + if (body instanceof Map) { + @SuppressWarnings("unchecked") + Map bodyMap = (Map) body; + String key = annotation.getValue(); + if ("*".equals(key) || key.isEmpty()) { + value.putAll(bodyMap); + } else { + value.put(key, bodyMap.get(key)); + } + } + } + } catch (IOException e) { + throw new DecodeException("Error reading input", e); + } + + return decoder.decode( + new ByteArrayInputStream(JsonUtils.toJson(value).getBytes(StandardCharsets.UTF_8)), + parameter.getType(), + StandardCharsets.UTF_8); + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/ParamArgumentResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/ParamArgumentResolver.java index 14e55e186b2..4e1bdf7029b 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/ParamArgumentResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/ParamArgumentResolver.java @@ -25,7 +25,6 @@ import org.apache.dubbo.remoting.http12.HttpRequest.FileUpload; import org.apache.dubbo.remoting.http12.HttpResponse; import org.apache.dubbo.remoting.http12.rest.Param; -import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; import org.apache.dubbo.rpc.protocol.tri.rest.RestException; @@ -49,13 +48,13 @@ public class ParamArgumentResolver extends AbstractAnnotationBaseArgumentResolver { @Override - protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann) { - String defaultValue = ann.getString("defaultValue"); + protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta anno) { + String defaultValue = anno.getString("defaultValue"); if (Param.DEFAULT_NONE.equals(defaultValue)) { defaultValue = null; } - ParamType paramType = ann.getEnum("type"); - return new ParamNamedValueMeta(ann.getValue(), ann.getBoolean("required"), defaultValue, paramType); + return new NamedValueMeta(anno.getValue(), anno.getBoolean("required"), defaultValue) + .setParamType(anno.getEnum("type")); } @Override @@ -65,13 +64,15 @@ public Class accept() { @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { - switch (((ParamNamedValueMeta) meta).paramType) { + switch (meta.paramType()) { case PathVariable: return resolvePathVariable(meta, request); case MatrixVariable: return CollectionUtils.first(resolveMatrixVariable(meta, request)); case Param: return request.parameter(meta.name()); + case Form: + return request.formParameter(meta.name()); case Header: return request.header(meta.name()); case Cookie: @@ -96,7 +97,7 @@ protected Object filterValue(Object value, NamedValueMeta meta) { @Override protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { - switch (((ParamNamedValueMeta) meta).paramType) { + switch (meta.paramType()) { case PathVariable: String value = resolvePathVariable(meta, request); return value == null ? Collections.emptyList() : Collections.singletonList(value); @@ -104,6 +105,8 @@ protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request return resolveMatrixVariable(meta, request); case Param: return request.parameterValues(meta.name()); + case Form: + return request.formParameterValues(meta.name()); case Header: return request.headerValues(meta.name()); case Cookie: @@ -142,7 +145,7 @@ protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request @Override protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { - switch (((ParamNamedValueMeta) meta).paramType) { + switch (meta.paramType()) { case PathVariable: String value = resolvePathVariable(meta, request); return value == null ? Collections.emptyMap() : Collections.singletonMap(meta.name(), value); @@ -150,8 +153,10 @@ protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpR return CollectionUtils.first(resolveMatrixVariable(meta, request)); case Param: return RequestUtils.getParametersMap(request); + case Form: + return RequestUtils.getFormParametersMap(request); case Header: - return request.headers(); + return request.headers().asMap(); case Cookie: Collection cookies = request.cookies(); if (cookies.isEmpty()) { @@ -204,14 +209,4 @@ private static List resolveMatrixVariable(NamedValueMeta meta, HttpReque Map variableMap = request.attribute(RestConstants.URI_TEMPLATE_VARIABLES_ATTRIBUTE); return RequestUtils.parseMatrixVariableValues(variableMap, meta.name()); } - - private static final class ParamNamedValueMeta extends NamedValueMeta { - - private final ParamType paramType; - - ParamNamedValueMeta(String name, boolean required, String defaultValue, ParamType paramType) { - super(name, required, defaultValue); - this.paramType = paramType; - } - } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/AbstractRestToolKit.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/AbstractRestToolKit.java index 7ddb719c583..772022bb8cc 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/AbstractRestToolKit.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/AbstractRestToolKit.java @@ -16,38 +16,47 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.util; -import org.apache.dubbo.common.config.Environment; import org.apache.dubbo.common.utils.AnnotationUtils; +import org.apache.dubbo.common.utils.DefaultParameterNameReader; +import org.apache.dubbo.common.utils.ParameterNameReader; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestException; +import org.apache.dubbo.rpc.protocol.tri.rest.argument.CompositeArgumentResolver; import org.apache.dubbo.rpc.protocol.tri.rest.argument.GeneralTypeConverter; import org.apache.dubbo.rpc.protocol.tri.rest.argument.TypeConverter; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; +import javax.annotation.Nullable; + import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; import java.lang.reflect.Method; -import java.lang.reflect.Parameter; import java.util.Map; public abstract class AbstractRestToolKit implements RestToolKit { protected final FrameworkModel frameworkModel; protected final TypeConverter typeConverter; + protected final ParameterNameReader parameterNameReader; + protected final CompositeArgumentResolver argumentResolver; public AbstractRestToolKit(FrameworkModel frameworkModel) { this.frameworkModel = frameworkModel; - typeConverter = frameworkModel.getBeanFactory().getOrRegisterBean(GeneralTypeConverter.class); + typeConverter = frameworkModel.getOrRegisterBean(GeneralTypeConverter.class); + parameterNameReader = frameworkModel.getOrRegisterBean(DefaultParameterNameReader.class); + argumentResolver = frameworkModel.getOrRegisterBean(CompositeArgumentResolver.class); } @Override public String resolvePlaceholders(String text) { - return RestUtils.hasPlaceholder(text) ? getEnvironment().resolvePlaceholders(text) : text; - } - - private Environment getEnvironment() { - return frameworkModel.defaultApplication().modelEnvironment(); + return RestUtils.replacePlaceholder(text, k -> frameworkModel + .defaultApplication() + .modelEnvironment() + .getConfiguration() + .getString(k)); } @Override @@ -64,19 +73,20 @@ public Object convert(Object value, ParameterMeta parameter) { return target; } + @Override + public NamedValueMeta getNamedValueMeta(ParameterMeta parameter) { + return argumentResolver.getNamedValueMeta(parameter); + } + @Override public String[] getParameterNames(Method method) { - Parameter[] parameters = method.getParameters(); - int len = parameters.length; - String[] names = new String[len]; - for (int i = 0; i < len; i++) { - Parameter param = parameters[i]; - if (!param.isNamePresent()) { - return null; - } - names[i] = param.getName(); - } - return names; + return parameterNameReader.readParameterNames(method); + } + + @Nullable + @Override + public String[] getParameterNames(Constructor ctor) { + return parameterNameReader.readParameterNames(ctor); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/MethodWalker.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/MethodWalker.java index ccb7e95fdcf..de5b63faf66 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/MethodWalker.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/MethodWalker.java @@ -82,7 +82,7 @@ private static Key of(Method method) { } @Override - @SuppressWarnings("EqualsWhichDoesntCheckParameterClass") + @SuppressWarnings({"EqualsWhichDoesntCheckParameterClass", "EqualsDoesntCheckParameterClass"}) public boolean equals(Object obj) { Key key = (Key) obj; return name.equals(key.name) && Arrays.equals(parameterTypes, key.parameterTypes); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/PathUtils.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/PathUtils.java index 609446f826c..621d0d85914 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/PathUtils.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/PathUtils.java @@ -70,6 +70,25 @@ public static boolean isDirectPath(@Nonnull String path) { return true; } + public static String join(String path1, String path2) { + if (StringUtils.isEmpty(path1)) { + return StringUtils.isEmpty(path2) ? StringUtils.EMPTY_STRING : path2; + } + if (StringUtils.isEmpty(path2)) { + return path1; + } + if (path1.charAt(path1.length() - 1) == '/') { + if (path2.charAt(0) == '/') { + return path1 + path2.substring(1); + } + return path1 + path2; + } + if (path2.charAt(0) == '/') { + return path1 + path2; + } + return path1 + '/' + path2; + } + /** * See * AntPathMatcher#combine @@ -121,6 +140,9 @@ public static String combine(@Nonnull String path1, @Nonnull String path2) { boolean slash1 = last1 == '/'; boolean slash2 = path2.charAt(0) == '/'; + if (slash2 && path2.length() > 1 && path2.charAt(1) == '/') { + return path2.substring(1); + } if (slash1) { return slash2 ? path1 + path2.substring(1) : path1 + path2; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RequestUtils.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RequestUtils.java index bb152cc7a6b..a471ef5be66 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RequestUtils.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RequestUtils.java @@ -46,6 +46,10 @@ public final class RequestUtils { private RequestUtils() {} + public static boolean isRestRequest(HttpRequest request) { + return request != null && request.hasAttribute(RestConstants.PATH_ATTRIBUTE); + } + public static boolean isMultiPart(HttpRequest request) { String contentType = request.contentType(); return contentType != null && contentType.startsWith(MediaType.MULTIPART_FORM_DATA.getName()); @@ -122,6 +126,19 @@ public static Map getParametersMapStartingWith(HttpRequest reque return params; } + public static String getPathVariable(HttpRequest request, String name) { + Map variableMap = request.attribute(RestConstants.URI_TEMPLATE_VARIABLES_ATTRIBUTE); + if (variableMap == null) { + return null; + } + String value = variableMap.get(name); + if (value == null) { + return null; + } + int index = value.indexOf(';'); + return decodeURL(index == -1 ? value : value.substring(0, index)); + } + public static Map> parseMatrixVariables(String matrixVariables) { Map> result = null; StringTokenizer pairs = new StringTokenizer(matrixVariables, ";"); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestToolKit.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestToolKit.java index 2ed7c511fbd..86deda314c4 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestToolKit.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestToolKit.java @@ -18,12 +18,14 @@ import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import javax.annotation.Nullable; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Map; @@ -37,8 +39,13 @@ public interface RestToolKit { Object bind(ParameterMeta parameter, HttpRequest request, HttpResponse response); + NamedValueMeta getNamedValueMeta(ParameterMeta parameter); + @Nullable String[] getParameterNames(Method method); + @Nullable + String[] getParameterNames(Constructor ctor); + Map getAttributes(AnnotatedElement element, Annotation annotation); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestUtils.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestUtils.java index 1155d3860a4..d14016640bc 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestUtils.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestUtils.java @@ -20,6 +20,8 @@ import org.apache.dubbo.common.lang.Prioritized; import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension; +import java.util.function.Function; + public final class RestUtils { private RestUtils() {} @@ -39,7 +41,7 @@ public static boolean hasPlaceholder(String text) { state = 1; } else if (c == '{') { if (state == 1) { - if (text.charAt(i + 1) != '$') { + if (text.charAt(i - 1) != '$') { return false; } state = 2; @@ -51,6 +53,150 @@ public static boolean hasPlaceholder(String text) { return false; } + public static String replacePlaceholder(String text, Function resolver) { + if (text == null) { + return null; + } + int len = text.length(); + if (len < 2) { + return text; + } + + int p = 0, nameStart = 0, nameEnd = 0, valueStart = 0, valueEnd = 0; + String value; + StringBuilder buf = null; + int state = State.START; + for (int i = 0; i < len; i++) { + char c = text.charAt(i); + switch (c) { + case '$': + if (state == State.START) { + if (buf == null) { + buf = new StringBuilder(len); + } + buf.append(text, p, i); + p = i; + state = State.DOLLAR; + } else if (state == State.DOLLAR) { + if (buf == null) { + buf = new StringBuilder(len); + } + buf.append(text, p, i - 1); + p = i; + state = State.START; + } + break; + case '{': + state = state == State.DOLLAR ? State.BRACE_OPEN : State.START; + break; + case ':': + state = state == State.NAME_START ? State.COLON : State.START; + break; + case '}': + switch (state) { + case State.DOLLAR: + case State.BRACE_OPEN: + state = State.START; + break; + case State.COLON: + state = State.START; + valueStart = i; + break; + case State.DOLLAR_NAME_START: + case State.NAME_START: + case State.VALUE_START: + value = resolver.apply(text.substring(nameStart, nameEnd)); + if (buf == null) { + buf = new StringBuilder(len); + } + if (value == null) { + if (state == State.VALUE_START) { + buf.append(text, valueStart, valueEnd); + } else { + buf.append(text, p, i + 1); + } + } else { + buf.append(value); + } + p = i + 1; + state = State.START; + break; + default: + } + break; + case ' ': + case '\t': + case '\n': + case '\r': + if (state == State.DOLLAR_NAME_START) { + state = State.START; + value = resolver.apply(text.substring(nameStart, nameEnd)); + if (buf == null) { + buf = new StringBuilder(len); + } + if (value == null) { + buf.append(text, p, i); + } else { + buf.append(value); + } + p = i; + } + break; + default: + switch (state) { + case State.DOLLAR: + state = State.DOLLAR_NAME_START; + nameStart = i; + break; + case State.BRACE_OPEN: + state = State.NAME_START; + nameStart = i; + break; + case State.COLON: + state = State.VALUE_START; + valueStart = i; + break; + case State.DOLLAR_NAME_START: + case State.NAME_START: + nameEnd = i + 1; + break; + case State.VALUE_START: + valueEnd = i + 1; + break; + default: + } + } + } + if (state == State.DOLLAR_NAME_START) { + value = resolver.apply(text.substring(nameStart, nameEnd)); + if (buf == null) { + buf = new StringBuilder(len); + } + if (value == null) { + buf.append(text, p, len); + } else { + buf.append(value); + } + } else { + if (buf == null) { + return text; + } + buf.append(text, p, len); + } + return buf.toString(); + } + + private interface State { + + int START = 0; + int DOLLAR = 1; + int BRACE_OPEN = 2; + int COLON = 3; + int DOLLAR_NAME_START = 4; + int NAME_START = 5; + int VALUE_START = 6; + } + public static boolean isMaybeJSONObject(String str) { if (str == null) { return false; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java index 60b551eed84..1bc6e2e9379 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java @@ -16,9 +16,13 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.util; +import org.apache.dubbo.common.stream.StreamObserver; import org.apache.dubbo.common.utils.ArrayUtils; import org.apache.dubbo.common.utils.ClassUtils; import org.apache.dubbo.common.utils.ConcurrentHashSet; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import java.io.File; import java.lang.reflect.Array; @@ -38,6 +42,7 @@ import java.time.ZoneId; import java.time.temporal.Temporal; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Currency; @@ -59,13 +64,16 @@ import java.util.TimeZone; import java.util.TreeMap; import java.util.UUID; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.regex.Pattern; public final class TypeUtils { private static final Set> SIMPLE_TYPES = new ConcurrentHashSet<>(); + private static final List SYSTEM_PREFIXES = new CopyOnWriteArrayList<>(); static { Collections.addAll( @@ -80,6 +88,8 @@ public final class TypeUtils { Currency.class, Pattern.class, Class.class); + + Collections.addAll(SYSTEM_PREFIXES, "java.", "javax.", "sun.", "com.sun.", "com.google.protobuf."); } private TypeUtils() {} @@ -112,6 +122,42 @@ private static boolean isSimpleValueType(Class type) { return false; } + public static void addSimpleTypes(Class... types) { + SIMPLE_TYPES.addAll(Arrays.asList(types)); + } + + public static List getSystemPrefixes() { + return SYSTEM_PREFIXES; + } + + public static void addSystemPrefixes(String... prefixes) { + for (String prefix : prefixes) { + if (StringUtils.isNotEmpty(prefix)) { + SYSTEM_PREFIXES.add(prefix); + } + } + } + + public static boolean isSystemType(Class type) { + String name = type.getName(); + List systemPrefixes = getSystemPrefixes(); + for (int i = systemPrefixes.size() - 1; i >= 0; i--) { + String prefix = systemPrefixes.get(i); + if (prefix.charAt(0) == '!') { + if (name.regionMatches(0, prefix, 1, prefix.length() - 1)) { + return false; + } + } else if (name.startsWith(prefix)) { + return true; + } + } + return false; + } + + public static boolean isWrapperType(Class type) { + return type == Optional.class || type == CompletableFuture.class || type == StreamObserver.class; + } + public static Class getMapValueType(Class targetClass) { for (Type gi : targetClass.getGenericInterfaces()) { if (gi instanceof ParameterizedType) { @@ -362,4 +408,95 @@ public static String buildSig(Method method) { } return sb.toString(); } + + public static String toTypeString(Type type) { + if (type instanceof Class) { + Class clazz = (Class) type; + return clazz.isArray() ? clazz.getComponentType().getName() + "[]" : clazz.getName(); + } + StringBuilder result = new StringBuilder(32); + buildGenericTypeString(type, result); + return result.toString(); + } + + private static void buildGenericTypeString(Type type, StringBuilder sb) { + if (type instanceof Class) { + Class clazz = (Class) type; + if (clazz.isArray()) { + buildGenericTypeString(clazz.getComponentType(), sb); + sb.append("[]"); + } else { + sb.append(clazz.getName()); + } + } else if (type instanceof ParameterizedType) { + ParameterizedType pzType = (ParameterizedType) type; + Type[] typeArgs = pzType.getActualTypeArguments(); + buildGenericTypeString(pzType.getRawType(), sb); + sb.append('<'); + for (int i = 0, len = typeArgs.length; i < len; i++) { + if (i > 0) { + sb.append(", "); + } + buildGenericTypeString(typeArgs[i], sb); + } + sb.append('>'); + } else if (type instanceof WildcardType) { + WildcardType wildcardType = (WildcardType) type; + Type[] upperBounds = wildcardType.getUpperBounds(); + Type[] lowerBounds = wildcardType.getLowerBounds(); + if (lowerBounds.length > 0) { + sb.append("? super "); + buildGenericTypeString(lowerBounds[0], sb); + } else if (upperBounds.length > 0 && upperBounds[0] != Object.class) { + sb.append("? extends "); + buildGenericTypeString(upperBounds[0], sb); + } else { + sb.append('?'); + } + } else if (type instanceof GenericArrayType) { + GenericArrayType genericArrayType = (GenericArrayType) type; + buildGenericTypeString(genericArrayType.getGenericComponentType(), sb); + sb.append("[]"); + } else if (type instanceof TypeVariable) { + TypeVariable typeVariable = (TypeVariable) type; + sb.append(typeVariable.getName()); + Type[] bounds = typeVariable.getBounds(); + int len = bounds.length; + if (len > 0 && !(len == 1 && bounds[0] == Object.class)) { + sb.append(" extends "); + for (int i = 0; i < len; i++) { + if (i > 0) { + sb.append(" & "); + } + buildGenericTypeString(bounds[i], sb); + } + } + } else { + sb.append(type.toString()); + } + } + + public static Object getMethodDescriptor(MethodMeta methodMeta) { + StringBuilder sb = new StringBuilder(64); + sb.append(toTypeString(methodMeta.getGenericReturnType())) + .append(' ') + .append(methodMeta.getMethod().getName()) + .append('('); + ParameterMeta[] parameters = methodMeta.getParameters(); + for (int i = 0, len = parameters.length; i < len; i++) { + if (i > 0) { + sb.append(", "); + } + ParameterMeta paramMeta = parameters[i]; + String name = paramMeta.getName(); + sb.append(toTypeString(paramMeta.getGenericType())).append(' '); + if (name == null) { + sb.append("arg").append(i + 1); + } else { + sb.append(name); + } + } + sb.append(')'); + return sb.toString(); + } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/AbstractStream.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/AbstractStream.java index f2f69bb344d..b73c5623e8a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/AbstractStream.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/AbstractStream.java @@ -30,7 +30,7 @@ public abstract class AbstractStream implements Stream { protected Executor executor; protected final FrameworkModel frameworkModel; - private static final boolean HAS_PROTOBUF = hasProtobuf(); + private static final boolean HAS_PROTOBUF = ClassUtils.hasProtobuf(); public AbstractStream(Executor executor, FrameworkModel frameworkModel) { this.executor = new SerializingExecutor(executor); @@ -44,13 +44,4 @@ public void setExecutor(Executor executor) { public static boolean getGrpcStatusDetailEnabled() { return HAS_PROTOBUF; } - - private static boolean hasProtobuf() { - try { - ClassUtils.forName("com.google.protobuf.Message"); - return true; - } catch (ClassNotFoundException ignore) { - return false; - } - } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/DefaultWebSocketServerTransportListener.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/DefaultWebSocketServerTransportListener.java new file mode 100644 index 00000000000..e43367d7b79 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/DefaultWebSocketServerTransportListener.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.dubbo.rpc.protocol.tri.websocket; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.remoting.http12.HttpHeaders; +import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; +import org.apache.dubbo.remoting.http12.h2.Http2Header; +import org.apache.dubbo.remoting.http12.h2.Http2InputMessage; +import org.apache.dubbo.remoting.http12.h2.Http2ServerChannelObserver; +import org.apache.dubbo.remoting.http12.message.StreamingDecoder; +import org.apache.dubbo.remoting.websocket.FinalFragmentStreamingDecoder; +import org.apache.dubbo.remoting.websocket.WebSocketHeaderNames; +import org.apache.dubbo.remoting.websocket.WebSocketTransportListener; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.model.MethodDescriptor.RpcType; +import org.apache.dubbo.rpc.protocol.tri.h12.http2.GenericHttp2ServerTransportListener; + +import java.util.concurrent.Executor; + +public class DefaultWebSocketServerTransportListener extends GenericHttp2ServerTransportListener + implements WebSocketTransportListener { + + private boolean autoClose = false; + + public DefaultWebSocketServerTransportListener( + H2StreamChannel h2StreamChannel, URL url, FrameworkModel frameworkModel) { + super(h2StreamChannel, url, frameworkModel); + } + + @Override + protected void onBeforeMetadata(Http2Header metadata) {} + + @Override + protected Executor initializeExecutor(URL url, Http2Header metadata) { + return getExecutor(url, metadata); + } + + @Override + protected void onPrepareMetadata(Http2Header metadata) { + doRoute(metadata); + } + + @Override + protected StreamingDecoder newStreamingDecoder() { + return new FinalFragmentStreamingDecoder(); + } + + @Override + protected Http2ServerChannelObserver newResponseObserver(H2StreamChannel h2StreamChannel) { + return new WebSocketServerChannelObserver(getFrameworkModel(), h2StreamChannel); + } + + @Override + protected Http2ServerChannelObserver newStreamResponseObserver(H2StreamChannel h2StreamChannel) { + return new WebSocketServerChannelObserver(getFrameworkModel(), h2StreamChannel); + } + + @Override + protected Http2ServerChannelObserver prepareResponseObserver(Http2ServerChannelObserver responseObserver) { + responseObserver.addTrailersCustomizer(this::customizeWebSocketStatus); + return super.prepareResponseObserver(responseObserver); + } + + @Override + protected void prepareUnaryServerCall() { + autoClose = true; + super.prepareUnaryServerCall(); + } + + @Override + protected void prepareStreamServerCall() { + if (getContext().getMethodDescriptor().getRpcType().equals(RpcType.SERVER_STREAM)) { + autoClose = true; + } + super.prepareStreamServerCall(); + } + + @Override + protected void onDataCompletion(Http2InputMessage message) { + if (autoClose) { + getStreamingDecoder().close(); + return; + } + super.onDataCompletion(message); + } + + private void customizeWebSocketStatus(HttpHeaders httpHeaders, Throwable throwable) { + if (throwable != null) { + httpHeaders.set(WebSocketHeaderNames.WEBSOCKET_MESSAGE.getName(), throwable.getMessage()); + } + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/DefaultWebSocketServerTransportListenerFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/DefaultWebSocketServerTransportListenerFactory.java new file mode 100644 index 00000000000..fd5c331f5e6 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/DefaultWebSocketServerTransportListenerFactory.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.dubbo.rpc.protocol.tri.websocket; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; +import org.apache.dubbo.remoting.websocket.WebSocketServerTransportListenerFactory; +import org.apache.dubbo.remoting.websocket.WebSocketTransportListener; +import org.apache.dubbo.rpc.model.FrameworkModel; + +public class DefaultWebSocketServerTransportListenerFactory implements WebSocketServerTransportListenerFactory { + + public static final WebSocketServerTransportListenerFactory INSTANCE = + new DefaultWebSocketServerTransportListenerFactory(); + + @Override + public WebSocketTransportListener newInstance( + H2StreamChannel streamChannel, URL url, FrameworkModel frameworkModel) { + return new DefaultWebSocketServerTransportListener(streamChannel, url, frameworkModel); + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/WebSocketServerChannelObserver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/WebSocketServerChannelObserver.java new file mode 100644 index 00000000000..3590dbc0269 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/websocket/WebSocketServerChannelObserver.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.dubbo.rpc.protocol.tri.websocket; + +import org.apache.dubbo.remoting.http12.HttpOutputMessage; +import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.h12.http2.Http2StreamServerChannelObserver; + +public class WebSocketServerChannelObserver extends Http2StreamServerChannelObserver { + + protected WebSocketServerChannelObserver(FrameworkModel frameworkModel, H2StreamChannel h2StreamChannel) { + super(frameworkModel, h2StreamChannel); + } + + @Override + protected void doOnNext(Object data) throws Throwable { + int statusCode = resolveStatusCode(data); + HttpOutputMessage httpOutputMessage = buildMessage(statusCode, data); + sendMessage(httpOutputMessage); + } + + @Override + protected void doOnError(Throwable throwable) {} +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.websocket.WebSocketServerTransportListenerFactory b/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.websocket.WebSocketServerTransportListenerFactory new file mode 100644 index 00000000000..eb51344a149 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.websocket.WebSocketServerTransportListenerFactory @@ -0,0 +1 @@ +default=org.apache.dubbo.rpc.protocol.tri.websocket.DefaultWebSocketServerTransportListenerFactory diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver b/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver index 0486f00884a..829c373182f 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver @@ -1,3 +1,4 @@ misc=org.apache.dubbo.rpc.protocol.tri.rest.argument.MiscArgumentResolver basic-param=org.apache.dubbo.rpc.protocol.tri.rest.support.basic.ParamArgumentResolver basic-fallback=org.apache.dubbo.rpc.protocol.tri.rest.support.basic.FallbackArgumentResolver +grpc-request=org.apache.dubbo.rpc.protocol.tri.rest.support.basic.GRequestArgumentResolver diff --git a/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTreeTest.groovy b/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTreeTest.groovy index b40080486d6..37cbb35c9ce 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTreeTest.groovy +++ b/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTreeTest.groovy @@ -58,4 +58,17 @@ class RadixTreeTest extends Specification { '/a/b/c' | 1 '/a/b/c/d' | 0 } + + def "test sub path match"() { + given: + def tree = new RadixTree(); + tree.addPath("/update/{ruleId}", "a") + tree.addPath("/update/{ruleId}/state", "b") + expect: + tree.match(path).get(0).value == result + where: + path | result + '/update/1222222' | 'a' + '/update/1222222/state' | 'b' + } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpressionTest.groovy b/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpressionTest.groovy index 1061fcea658..19ad12542fc 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpressionTest.groovy +++ b/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpressionTest.groovy @@ -206,6 +206,7 @@ class PathExpressionTest extends Specification { '/one' | '/one' | 0 '/one' | '/two' | 0 '/one/{two}/three' | '/one/{t}/three' | 0 + '/one/two' | '/one/{two}' | -1 '/one/{two}/three' | '/one/*/three' | -1 '/one/*/three' | '/one/**/three' | -1 '/one/two' | '/one' | -1 diff --git a/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/RestProtocolTest.groovy b/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/RestProtocolTest.groovy index 4b3547d238d..dc2ffb9332f 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/RestProtocolTest.groovy +++ b/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/RestProtocolTest.groovy @@ -24,6 +24,9 @@ import org.apache.dubbo.rpc.protocol.tri.rest.test.BaseServiceTest import org.apache.dubbo.rpc.protocol.tri.test.TestRequest import org.apache.dubbo.rpc.protocol.tri.test.TestRunnerBuilder +import io.netty.buffer.AbstractByteBuf +import io.netty.util.ResourceLeakDetector + class RestProtocolTest extends BaseServiceTest { @Override @@ -174,6 +177,30 @@ class RestProtocolTest extends BaseServiceTest { '/argTest' | 'Sam is 8 years old' } + @SuppressWarnings('GroovyAccessibility') + def "urlEncodeForm body test"() { + given: + def level = ResourceLeakDetector.level + def leaks = AbstractByteBuf.leakDetector.allLeaks + ResourceLeakDetector.level = ResourceLeakDetector.Level.PARANOID + leaks.clear() + and: + def request = new TestRequest( + path: path, + contentType: MediaType.APPLICATION_FROM_URLENCODED, + body: body + ) + expect: + runner.post(request) == output + leaks.empty + cleanup: + ResourceLeakDetector.level = level + where: + path | body | output + '/argTest' | 'name=Sam&age=8' | 'Sam is 8 years old' + '/argTest' | '' | 'null is 0 years old' + } + def "override mapping test"() { expect: runner.get(path) == output @@ -241,7 +268,40 @@ class RestProtocolTest extends BaseServiceTest { path | accept | output '/produceTest?name=world' | '' | 'world' '/produceTest?name=world' | 'text/plain' | 'world' - '/produceTest?name=world' | 'application/json' | '{"message":"Invoker not found","status":"404"}' + '/produceTest?name=world' | 'application/json' | '{"message":"Could not find acceptable representation","status":"406"}' + } + + def "mismatch test"() { + given: + def request = new TestRequest( + method: method, + path: path, + contentType: contentType, + accept: accept + ) + expect: + runner.run(request, String.class) == output + where: + method | path | contentType | accept | output + 'POST' | '/mismatchTest?name=world' | 'text/plain' | 'text/plain' | 'world' + 'POST' | '/mismatchTest1' | 'text/plain' | 'text/plain' | '{"message":"Invoker not found","status":"404"}' + 'GET' | '/mismatchTest' | '' | '' | '{"message":"Request method \'GET\' not supported","status":"405"}' + 'POST' | '/mismatchTest' | 'application/json' | 'text/plain' | '{"message":"Content type \'application/json\' not supported","status":"415"}' + 'POST' | '/mismatchTest' | 'text/plain' | 'application/json' | '{"message":"Could not find acceptable representation","status":"406"}' + 'POST' | '/mismatchTest?name=earth' | 'text/plain' | 'text/plain' | '{"message":"Unsatisfied query parameter conditions","status":"400"}' + } + + def "consistent with SpringMVC"() { + given: + def request = new TestRequest( + path: path, + accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8' + ) + expect: + runner.run(request).contentType == contentType + where: + path | contentType + '/beanArgTest' | 'application/json' } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/TripleHttp3ProtocolTest.java b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/TripleHttp3ProtocolTest.java index 342825c3d31..b53fc27f350 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/TripleHttp3ProtocolTest.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/TripleHttp3ProtocolTest.java @@ -108,7 +108,7 @@ void testDemoProtocol() throws Exception { MockStreamObserver outboundMessageSubscriber1 = new MockStreamObserver(); greeterProxy.serverStream(REQUEST_MSG, outboundMessageSubscriber1); outboundMessageSubscriber1.getLatch().await(3000, TimeUnit.MILLISECONDS); - Assertions.assertEquals(outboundMessageSubscriber1.getOnNextData(), REQUEST_MSG); + Assertions.assertEquals(REQUEST_MSG, outboundMessageSubscriber1.getOnNextData()); Assertions.assertTrue(outboundMessageSubscriber1.isOnCompleted()); // 3. test bidirectionalStream @@ -118,7 +118,7 @@ void testDemoProtocol() throws Exception { inboundMessageObserver.onCompleted(); outboundMessageSubscriber2.getLatch().await(3000, TimeUnit.MILLISECONDS); // verify client - Assertions.assertEquals(outboundMessageSubscriber2.getOnNextData(), IGreeter.SERVER_MSG); + Assertions.assertEquals(IGreeter.SERVER_MSG, outboundMessageSubscriber2.getOnNextData()); Assertions.assertTrue(outboundMessageSubscriber2.isOnCompleted()); // verify server MockStreamObserver serverOutboundMessageSubscriber = (MockStreamObserver) serviceImpl.getMockStreamObserver(); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/service/DemoService.java b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/service/DemoService.java index 8469f14080d..b9597f057a0 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/service/DemoService.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/service/DemoService.java @@ -17,6 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.rest.service; import org.apache.dubbo.common.stream.StreamObserver; +import org.apache.dubbo.remoting.http12.HttpMethods; import org.apache.dubbo.remoting.http12.rest.Mapping; import org.apache.dubbo.remoting.http12.rest.Param; import org.apache.dubbo.rpc.protocol.tri.rest.service.User.Group; @@ -71,4 +72,7 @@ public interface DemoService { @Mapping(produces = "text/plain") String produceTest(String name); + + @Mapping(method = HttpMethods.POST, consumes = "text/plain", produces = "text/plain", params = "name=world") + String mismatchTest(String name); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/service/DemoServiceImpl.java b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/service/DemoServiceImpl.java index 767cd7e6840..b5575fdbae3 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/service/DemoServiceImpl.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/service/DemoServiceImpl.java @@ -148,4 +148,9 @@ public void pbServerStream(HealthCheckRequest request, StreamObserver List getBodies(Class type) { List bodies = (List) this.bodies; if (bodies == null) { bodies = new ArrayList<>(oss.size()); - for (OutputStream os : oss) { - ByteArrayOutputStream bos = (ByteArrayOutputStream) os; + boolean isTextEvent = MediaType.TEXT_EVENT_STREAM.getName().equals(getContentType()); + for (int i = 0, size = oss.size(); i < size; i++) { + if (isTextEvent && i % 3 != 1) { + continue; + } + ByteArrayOutputStream bos = (ByteArrayOutputStream) oss.get(i); if (bos.size() == 0) { bodies.add(null); } else { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/test/TestRunnerImpl.java b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/test/TestRunnerImpl.java index c5df5c2db9d..439b96fb329 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/test/TestRunnerImpl.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/test/TestRunnerImpl.java @@ -92,7 +92,7 @@ private void registerProvider(TProvider provider, Protocol protocol, Prox } @Override - @SuppressWarnings({"unchecked", "resource"}) + @SuppressWarnings("unchecked") public TestResponse run(TestRequest request) { MockH2StreamChannel channel = new MockH2StreamChannel(); URL url = new URL(TestProtocol.NAME, TestProtocol.HOST, TestProtocol.PORT, request.getProviderParams()); diff --git a/dubbo-serialization/dubbo-serialization-api/src/main/java/org/apache/dubbo/common/serialize/SerializationScopeModelInitializer.java b/dubbo-serialization/dubbo-serialization-api/src/main/java/org/apache/dubbo/common/serialize/SerializationScopeModelInitializer.java index 184bdb7df89..7f382c43ced 100644 --- a/dubbo-serialization/dubbo-serialization-api/src/main/java/org/apache/dubbo/common/serialize/SerializationScopeModelInitializer.java +++ b/dubbo-serialization/dubbo-serialization-api/src/main/java/org/apache/dubbo/common/serialize/SerializationScopeModelInitializer.java @@ -17,9 +17,7 @@ package org.apache.dubbo.common.serialize; import org.apache.dubbo.common.serialize.support.PreferSerializationProviderImpl; -import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; public class SerializationScopeModelInitializer implements ScopeModelInitializer { @@ -27,10 +25,4 @@ public class SerializationScopeModelInitializer implements ScopeModelInitializer public void initializeFrameworkModel(FrameworkModel frameworkModel) { frameworkModel.getBeanFactory().registerBean(PreferSerializationProviderImpl.class); } - - @Override - public void initializeApplicationModel(ApplicationModel applicationModel) {} - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/Fastjson2ScopeModelInitializer.java b/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/Fastjson2ScopeModelInitializer.java index 029839fa75e..fad45c6e996 100644 --- a/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/Fastjson2ScopeModelInitializer.java +++ b/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/Fastjson2ScopeModelInitializer.java @@ -17,9 +17,7 @@ package org.apache.dubbo.common.serialize.fastjson2; import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; -import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; public class Fastjson2ScopeModelInitializer implements ScopeModelInitializer { @@ -38,10 +36,4 @@ public void initializeFrameworkModel(FrameworkModel frameworkModel) { beanFactory.registerBean(Fastjson2SecurityManager.class); } } - - @Override - public void initializeApplicationModel(ApplicationModel applicationModel) {} - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2ScopeModelInitializer.java b/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2ScopeModelInitializer.java index 2ca838cb074..71fa7738de8 100644 --- a/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2ScopeModelInitializer.java +++ b/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2ScopeModelInitializer.java @@ -17,9 +17,7 @@ package org.apache.dubbo.common.serialize.hessian2; import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; -import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; public class Hessian2ScopeModelInitializer implements ScopeModelInitializer { @@ -38,10 +36,4 @@ public void initializeFrameworkModel(FrameworkModel frameworkModel) { frameworkModel.addClassLoaderListener(new Hessian2ClassLoaderListener()); } } - - @Override - public void initializeApplicationModel(ApplicationModel applicationModel) {} - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2SerializerFactory.java b/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2SerializerFactory.java index 4f02609dfe6..f907e164445 100644 --- a/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2SerializerFactory.java +++ b/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2SerializerFactory.java @@ -18,11 +18,15 @@ import org.apache.dubbo.common.utils.DefaultSerializeClassChecker; +import java.io.InputStream; import java.io.Serializable; import com.alibaba.com.caucho.hessian.io.Deserializer; +import com.alibaba.com.caucho.hessian.io.InputStreamDeserializer; import com.alibaba.com.caucho.hessian.io.JavaDeserializer; import com.alibaba.com.caucho.hessian.io.JavaSerializer; +import com.alibaba.com.caucho.hessian.io.RecordDeserializer; +import com.alibaba.com.caucho.hessian.io.RecordUtil; import com.alibaba.com.caucho.hessian.io.Serializer; import com.alibaba.com.caucho.hessian.io.SerializerFactory; import com.alibaba.com.caucho.hessian.io.UnsafeDeserializer; @@ -63,6 +67,10 @@ protected Serializer getDefaultSerializer(Class cl) { @Override protected Deserializer getDefaultDeserializer(Class cl) { + if (InputStream.class.equals(cl)) { + return InputStreamDeserializer.DESER; + } + try { // pre-check if class is allow defaultSerializeClassChecker.loadClass(getClassLoader(), cl.getName()); @@ -72,9 +80,13 @@ protected Deserializer getDefaultDeserializer(Class cl) { checkSerializable(cl); - if (isEnableUnsafeSerializer()) { - return new UnsafeDeserializer(cl, getFieldDeserializerFactory()); - } else return new JavaDeserializer(cl, getFieldDeserializerFactory()); + if (RecordUtil.isRecord(cl)) { + return new RecordDeserializer(cl, getFieldDeserializerFactory()); + } else { + if (isEnableUnsafeSerializer()) { + return new UnsafeDeserializer(cl, getFieldDeserializerFactory()); + } else return new JavaDeserializer(cl, getFieldDeserializerFactory()); + } } private void checkSerializable(Class cl) { diff --git a/dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/pom.xml b/dubbo-spring-boot-project/dubbo-spring-boot-3-autoconfigure/pom.xml similarity index 77% rename from dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/pom.xml rename to dubbo-spring-boot-project/dubbo-spring-boot-3-autoconfigure/pom.xml index e65cf6bf5fd..99ea0181322 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/pom.xml +++ b/dubbo-spring-boot-project/dubbo-spring-boot-3-autoconfigure/pom.xml @@ -28,16 +28,12 @@ jar Apache Dubbo Spring Boot 3 Auto-Configure - - 3.2.1 - - org.springframework.boot spring-boot-dependencies - ${spring-boot.version} + ${spring-boot-3.version} pom import @@ -67,10 +63,34 @@ true + + org.apache.dubbo + dubbo-triple-websocket + ${project.version} + true + + jakarta.servlet jakarta.servlet-api - true + provided + + + org.apache.tomcat.embed + tomcat-embed-core + provided + + + + jakarta.websocket + jakarta.websocket-api + provided + + + + jakarta.websocket + jakarta.websocket-client-api + provided diff --git a/dubbo-spring-boot-project/dubbo-spring-boot-3-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboTriple3AutoConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-3-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboTriple3AutoConfiguration.java new file mode 100644 index 00000000000..08ab713a552 --- /dev/null +++ b/dubbo-spring-boot-project/dubbo-spring-boot-3-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboTriple3AutoConfiguration.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.dubbo.spring.boot.autoconfigure; + +import org.apache.dubbo.rpc.protocol.tri.ServletExchanger; +import org.apache.dubbo.rpc.protocol.tri.servlet.jakarta.TripleFilter; +import org.apache.dubbo.rpc.protocol.tri.websocket.jakarta.TripleWebSocketFilter; + +import jakarta.servlet.Filter; +import org.apache.coyote.ProtocolHandler; +import org.apache.coyote.UpgradeProtocol; +import org.apache.coyote.http2.Http2Protocol; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; +import org.springframework.boot.web.embedded.tomcat.ConfigurableTomcatWebServerFactory; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +@Conditional(SpringBoot3Condition.class) +public class DubboTriple3AutoConfiguration { + + public static final String SERVLET_PREFIX = "dubbo.protocol.triple.servlet"; + + public static final String WEBSOCKET_PREFIX = "dubbo.protocol.triple.websocket"; + + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(Filter.class) + @ConditionalOnWebApplication(type = Type.SERVLET) + @ConditionalOnProperty(prefix = SERVLET_PREFIX, name = "enabled", havingValue = "true") + public static class TripleServletConfiguration { + + @Bean + public FilterRegistrationBean tripleProtocolFilter( + @Value("${" + SERVLET_PREFIX + ".filter-url-patterns:/*}") String[] urlPatterns, + @Value("${" + SERVLET_PREFIX + ".filter-order:-1000000}") int order, + @Value("${server.port:8080}") int serverPort) { + ServletExchanger.bindServerPort(serverPort); + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(new TripleFilter()); + registrationBean.addUrlPatterns(urlPatterns); + registrationBean.setOrder(order); + return registrationBean; + } + + @Bean + @ConditionalOnClass(Http2Protocol.class) + @ConditionalOnProperty(prefix = SERVLET_PREFIX, name = "max-concurrent-streams") + public WebServerFactoryCustomizer tripleTomcatHttp2Customizer( + @Value("${" + SERVLET_PREFIX + ".max-concurrent-streams}") int maxConcurrentStreams) { + return factory -> factory.addConnectorCustomizers(connector -> { + ProtocolHandler handler = connector.getProtocolHandler(); + for (UpgradeProtocol upgradeProtocol : handler.findUpgradeProtocols()) { + if (upgradeProtocol instanceof Http2Protocol) { + Http2Protocol protocol = (Http2Protocol) upgradeProtocol; + int value = maxConcurrentStreams <= 0 ? Integer.MAX_VALUE : maxConcurrentStreams; + protocol.setMaxConcurrentStreams(value); + protocol.setMaxConcurrentStreamExecution(value); + } + } + }); + } + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(Filter.class) + @ConditionalOnWebApplication(type = Type.SERVLET) + @ConditionalOnProperty(prefix = WEBSOCKET_PREFIX, name = "enabled", havingValue = "true") + public static class TripleWebSocketConfiguration { + + @Bean + public FilterRegistrationBean tripleWebSocketFilter( + @Value("${" + WEBSOCKET_PREFIX + ".filter-url-patterns:/*}") String[] urlPatterns, + @Value("${" + WEBSOCKET_PREFIX + ".filter-order:-1000000}") int order, + @Value("${server.port:8080}") int serverPort) { + ServletExchanger.bindServerPort(serverPort); + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(new TripleWebSocketFilter()); + registrationBean.addUrlPatterns(urlPatterns); + registrationBean.setOrder(order); + return registrationBean; + } + } +} diff --git a/dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/SpringBoot3Condition.java b/dubbo-spring-boot-project/dubbo-spring-boot-3-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/SpringBoot3Condition.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/SpringBoot3Condition.java rename to dubbo-spring-boot-project/dubbo-spring-boot-3-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/SpringBoot3Condition.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/src/main/resources/META-INF/spring.factories b/dubbo-spring-boot-project/dubbo-spring-boot-3-autoconfigure/src/main/resources/META-INF/spring.factories similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/src/main/resources/META-INF/spring.factories rename to dubbo-spring-boot-project/dubbo-spring-boot-3-autoconfigure/src/main/resources/META-INF/spring.factories diff --git a/dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/dubbo-spring-boot-project/dubbo-spring-boot-3-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports rename to dubbo-spring-boot-project/dubbo-spring-boot-3-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/pom.xml b/dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/pom.xml similarity index 57% rename from dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/pom.xml rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/pom.xml index 2869a1dbff6..27d7f6f39e7 100644 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/pom.xml +++ b/dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/pom.xml @@ -15,106 +15,130 @@ See the License for the specific language governing permissions and limitations under the License. --> - + 4.0.0 org.apache.dubbo - dubbo-demo-xml + dubbo-parent ${revision} - ../pom.xml + ../../pom.xml - dubbo-demo-xml-provider - jar - ${project.artifactId} - The demo provider module of dubbo project - - true - + dubbo-spring-boot-actuator-autoconfigure + Apache Dubbo Spring Boot Actuator Autoconfigure + - org.apache.dubbo - dubbo-demo-interface - ${project.parent.version} + org.springframework.boot + spring-boot-starter-web + true + - org.apache.dubbo - dubbo-registry-multicast - ${project.version} + org.apache.tomcat.embed + tomcat-embed-core + true + org.apache.dubbo - dubbo-registry-zookeeper + dubbo-spring-boot-actuator ${project.version} + + + org.springframework.boot + spring-boot-actuator-autoconfigure + true + + + org.apache.dubbo - dubbo-registry-nacos + dubbo-spring-boot-autoconfigure ${project.version} + + - com.alibaba.nacos - nacos-client + org.springframework.boot + spring-boot-configuration-processor + true + org.apache.dubbo - dubbo-configcenter-zookeeper + dubbo-spring-boot-actuator-autoconfigure-compatible ${project.version} + org.apache.dubbo - dubbo-configcenter-nacos + dubbo ${project.version} + org.apache.dubbo - dubbo-metadata-report-zookeeper + dubbo-common ${project.version} + true + org.apache.dubbo - dubbo-metadata-report-nacos + dubbo-config-spring ${project.version} + true + org.apache.dubbo dubbo-rpc-dubbo ${project.version} + test + org.apache.dubbo - dubbo-config-spring + dubbo-qos ${project.version} + true + + - org.apache.dubbo - dubbo-remoting-netty4 - ${project.version} + org.springframework.boot + spring-boot-starter-test + test - org.apache.dubbo - dubbo-serialization-hessian2 - ${project.version} + org.springframework.boot + spring-boot-starter-log4j2 + test + - org.apache.dubbo - dubbo-serialization-fastjson2 - ${project.version} + net.bytebuddy + byte-buddy + test - org.apache.dubbo - dubbo-rpc-triple - ${project.version} + net.bytebuddy + byte-buddy-agent + test org.apache.dubbo - dubbo-qos - ${project.version} + dubbo-test-check + ${project.parent.version} + test org.apache.logging.log4j log4j-slf4j-impl + test diff --git a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointAnnotationAutoConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointAnnotationAutoConfiguration.java similarity index 95% rename from dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointAnnotationAutoConfiguration.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointAnnotationAutoConfiguration.java index 93ff379073c..e132ace7523 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointAnnotationAutoConfiguration.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointAnnotationAutoConfiguration.java @@ -17,8 +17,8 @@ package org.apache.dubbo.spring.boot.actuate.autoconfigure; import org.apache.dubbo.spring.boot.actuate.endpoint.DubboConfigsMetadataEndpoint; -import org.apache.dubbo.spring.boot.actuate.endpoint.DubboMetadataEndpoint; import org.apache.dubbo.spring.boot.actuate.endpoint.DubboPropertiesMetadataEndpoint; +import org.apache.dubbo.spring.boot.actuate.endpoint.DubboQosEndpoints; import org.apache.dubbo.spring.boot.actuate.endpoint.DubboReferencesMetadataEndpoint; import org.apache.dubbo.spring.boot.actuate.endpoint.DubboServicesMetadataEndpoint; import org.apache.dubbo.spring.boot.actuate.endpoint.DubboShutdownEndpoint; @@ -52,8 +52,8 @@ public class DubboEndpointAnnotationAutoConfiguration { @ConditionalOnMissingBean @ConditionalOnAvailableEndpoint @CompatibleConditionalOnEnabledEndpoint - public DubboMetadataEndpoint dubboEndpoint() { - return new DubboMetadataEndpoint(); + public DubboQosEndpoints dubboQosEndpoints() { + return new DubboQosEndpoints(); } @Bean diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointMetadataAutoConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointMetadataAutoConfiguration.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointMetadataAutoConfiguration.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointMetadataAutoConfiguration.java diff --git a/dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboExtensionEndpointAutoConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboExtensionEndpointAutoConfiguration.java new file mode 100644 index 00000000000..87042c122cf --- /dev/null +++ b/dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboExtensionEndpointAutoConfiguration.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.dubbo.spring.boot.actuate.autoconfigure; + +import org.apache.dubbo.spring.boot.actuate.endpoint.DubboActuatorProperties; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +import static org.apache.dubbo.spring.boot.util.DubboUtils.DUBBO_PREFIX; + +/** + * Dubbo Extension Endpoints Auto-{@link Configuration} + */ +@ConditionalOnProperty(prefix = DUBBO_PREFIX, name = "enabled", matchIfMissing = true) +@ConditionalOnClass(name = {"org.springframework.boot.actuate.health.Health"}) +@Configuration +@AutoConfigureAfter( + name = {"org.apache.dubbo.spring.boot.actuate.autoconfigure.DubboEndpointMetadataAutoConfiguration"}) +@ComponentScan(basePackageClasses = DubboActuatorProperties.class) +public class DubboExtensionEndpointAutoConfiguration {} diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboHealthIndicatorAutoConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboHealthIndicatorAutoConfiguration.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboHealthIndicatorAutoConfiguration.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboHealthIndicatorAutoConfiguration.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboMetricsAutoConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboMetricsAutoConfiguration.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboMetricsAutoConfiguration.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboMetricsAutoConfiguration.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/resources/META-INF/spring.factories b/dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories similarity index 56% rename from dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/resources/META-INF/spring.factories rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories index 959f1a96ab4..83c854417b6 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/resources/META-INF/spring.factories +++ b/dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories @@ -1,3 +1,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +org.apache.dubbo.spring.boot.actuate.autoconfigure.DubboHealthIndicatorAutoConfiguration,\ +org.apache.dubbo.spring.boot.actuate.autoconfigure.DubboEndpointMetadataAutoConfiguration,\ org.apache.dubbo.spring.boot.actuate.autoconfigure.DubboEndpointAnnotationAutoConfiguration,\ org.apache.dubbo.spring.boot.actuate.autoconfigure.DubboMetricsAutoConfiguration diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports similarity index 54% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index adb80652d81..0522f42c684 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -1,3 +1,5 @@ -org.apache.dubbo.spring.boot.actuate.autoconfigure.DubboEndpointAutoConfiguration org.apache.dubbo.spring.boot.actuate.autoconfigure.DubboHealthIndicatorAutoConfiguration org.apache.dubbo.spring.boot.actuate.autoconfigure.DubboEndpointMetadataAutoConfiguration +org.apache.dubbo.spring.boot.actuate.autoconfigure.DubboExtensionEndpointAutoConfiguration +org.apache.dubbo.spring.boot.actuate.autoconfigure.DubboEndpointAnnotationAutoConfiguration +org.apache.dubbo.spring.boot.actuate.autoconfigure.DubboMetricsAutoConfiguration diff --git a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/test/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointAnnotationAutoConfigurationTest.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointAnnotationAutoConfigurationTest.java similarity index 76% rename from dubbo-spring-boot/dubbo-spring-boot-actuator/src/test/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointAnnotationAutoConfigurationTest.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointAnnotationAutoConfigurationTest.java index 1999808e7b9..7b7b2c964e6 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/test/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointAnnotationAutoConfigurationTest.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointAnnotationAutoConfigurationTest.java @@ -21,8 +21,8 @@ import org.apache.dubbo.config.annotation.DubboService; import org.apache.dubbo.config.bootstrap.DubboBootstrap; import org.apache.dubbo.spring.boot.actuate.endpoint.DubboConfigsMetadataEndpoint; -import org.apache.dubbo.spring.boot.actuate.endpoint.DubboMetadataEndpoint; import org.apache.dubbo.spring.boot.actuate.endpoint.DubboPropertiesMetadataEndpoint; +import org.apache.dubbo.spring.boot.actuate.endpoint.DubboQosEndpoints; import org.apache.dubbo.spring.boot.actuate.endpoint.DubboReferencesMetadataEndpoint; import org.apache.dubbo.spring.boot.actuate.endpoint.DubboServicesMetadataEndpoint; import org.apache.dubbo.spring.boot.actuate.endpoint.DubboShutdownEndpoint; @@ -33,7 +33,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Assert; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; @@ -47,6 +46,11 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.web.client.RestTemplate; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * {@link DubboEndpointAnnotationAutoConfiguration} Test * @@ -86,7 +90,7 @@ class DubboEndpointAnnotationAutoConfigurationTest { @Autowired - private DubboMetadataEndpoint dubboEndpoint; + private DubboQosEndpoints dubboQosEndpoints; @Autowired private DubboConfigsMetadataEndpoint dubboConfigsMetadataEndpoint; @@ -112,12 +116,12 @@ class DubboEndpointAnnotationAutoConfigurationTest { private String actuatorBaseURL; @BeforeEach - public void init() { + void init() { DubboBootstrap.reset(); } @AfterEach - public void destroy() { + void destroy() { DubboBootstrap.reset(); } @@ -128,10 +132,10 @@ void testShutdown() throws Exception { Map shutdownCounts = (Map) value.get("shutdown.count"); - Assert.assertEquals(0, shutdownCounts.get("registries")); - Assert.assertEquals(1, shutdownCounts.get("protocols")); - Assert.assertEquals(1, shutdownCounts.get("services")); - Assert.assertEquals(0, shutdownCounts.get("references")); + assertEquals(0, shutdownCounts.get("registries")); + assertEquals(1, shutdownCounts.get("protocols")); + assertEquals(1, shutdownCounts.get("services")); + assertEquals(0, shutdownCounts.get("references")); } @Test @@ -140,35 +144,35 @@ void testConfigs() { Map>> configsMap = dubboConfigsMetadataEndpoint.configs(); Map> beansMetadata = configsMap.get("ApplicationConfig"); - Assert.assertEquals( + assertEquals( "dubbo-demo-application", beansMetadata.get("my-application").get("name")); beansMetadata = configsMap.get("ConsumerConfig"); - Assert.assertTrue(beansMetadata.isEmpty()); + assertTrue(beansMetadata.isEmpty()); beansMetadata = configsMap.get("MethodConfig"); - Assert.assertTrue(beansMetadata.isEmpty()); + assertTrue(beansMetadata.isEmpty()); beansMetadata = configsMap.get("ModuleConfig"); - Assert.assertEquals("dubbo-demo-module", beansMetadata.get("my-module").get("name")); + assertEquals("dubbo-demo-module", beansMetadata.get("my-module").get("name")); beansMetadata = configsMap.get("MonitorConfig"); - Assert.assertTrue(beansMetadata.isEmpty()); + assertTrue(beansMetadata.isEmpty()); beansMetadata = configsMap.get("ProtocolConfig"); - Assert.assertEquals("dubbo", beansMetadata.get("my-protocol").get("name")); + assertEquals("dubbo", beansMetadata.get("my-protocol").get("name")); beansMetadata = configsMap.get("ProviderConfig"); - Assert.assertEquals("127.0.0.1", beansMetadata.get("my-provider").get("host")); + assertEquals("127.0.0.1", beansMetadata.get("my-provider").get("host")); beansMetadata = configsMap.get("ReferenceConfig"); - Assert.assertTrue(beansMetadata.isEmpty()); + assertTrue(beansMetadata.isEmpty()); beansMetadata = configsMap.get("RegistryConfig"); - Assert.assertEquals("N/A", beansMetadata.get("my-registry").get("address")); + assertEquals("N/A", beansMetadata.get("my-registry").get("address")); beansMetadata = configsMap.get("ServiceConfig"); - Assert.assertFalse(beansMetadata.isEmpty()); + assertFalse(beansMetadata.isEmpty()); } @Test @@ -176,12 +180,12 @@ void testServices() { Map> services = dubboServicesMetadataEndpoint.services(); - Assert.assertEquals(1, services.size()); + assertEquals(1, services.size()); Map demoServiceMeta = services.get( "ServiceBean:org.apache.dubbo.spring.boot.actuate.autoconfigure.DubboEndpointAnnotationAutoConfigurationTest$DemoService:1.0.0:"); - Assert.assertEquals("1.0.0", demoServiceMeta.get("version")); + assertEquals("1.0.0", demoServiceMeta.get("version")); } @Test @@ -189,13 +193,13 @@ void testReferences() { Map> references = dubboReferencesMetadataEndpoint.references(); - Assert.assertTrue(!references.isEmpty()); + assertFalse(references.isEmpty()); String injectedField = "private " + DemoService.class.getName() + " " + ConsumerConfiguration.class.getName() + ".demoService"; Map referenceMap = references.get(injectedField); - Assert.assertNotNull(referenceMap); - Assert.assertEquals(DemoService.class, referenceMap.get("interfaceClass")); - Assert.assertEquals( + assertNotNull(referenceMap); + assertEquals(DemoService.class, referenceMap.get("interfaceClass")); + assertEquals( BaseServiceMetadata.buildServiceKey( DemoService.class.getName(), ConsumerConfiguration.DEMO_GROUP, @@ -208,24 +212,23 @@ void testProperties() { SortedMap properties = dubboPropertiesEndpoint.properties(); - Assert.assertEquals("my-application", properties.get("dubbo.application.id")); - Assert.assertEquals("dubbo-demo-application", properties.get("dubbo.application.name")); - Assert.assertEquals("my-module", properties.get("dubbo.module.id")); - Assert.assertEquals("dubbo-demo-module", properties.get("dubbo.module.name")); - Assert.assertEquals("my-registry", properties.get("dubbo.registry.id")); - Assert.assertEquals("N/A", properties.get("dubbo.registry.address")); - Assert.assertEquals("my-protocol", properties.get("dubbo.protocol.id")); - Assert.assertEquals("dubbo", properties.get("dubbo.protocol.name")); - Assert.assertEquals("20880", properties.get("dubbo.protocol.port")); - Assert.assertEquals("my-provider", properties.get("dubbo.provider.id")); - Assert.assertEquals("127.0.0.1", properties.get("dubbo.provider.host")); - Assert.assertEquals( - "org.apache.dubbo.spring.boot.actuate.autoconfigure", properties.get("dubbo.scan.basePackages")); + assertEquals("my-application", properties.get("dubbo.application.id")); + assertEquals("dubbo-demo-application", properties.get("dubbo.application.name")); + assertEquals("my-module", properties.get("dubbo.module.id")); + assertEquals("dubbo-demo-module", properties.get("dubbo.module.name")); + assertEquals("my-registry", properties.get("dubbo.registry.id")); + assertEquals("N/A", properties.get("dubbo.registry.address")); + assertEquals("my-protocol", properties.get("dubbo.protocol.id")); + assertEquals("dubbo", properties.get("dubbo.protocol.name")); + assertEquals("20880", properties.get("dubbo.protocol.port")); + assertEquals("my-provider", properties.get("dubbo.provider.id")); + assertEquals("127.0.0.1", properties.get("dubbo.provider.host")); + assertEquals("org.apache.dubbo.spring.boot.actuate.autoconfigure", properties.get("dubbo.scan.basePackages")); } @Test void testHttpEndpoints() throws JsonProcessingException { - // testHttpEndpoint("/dubbo", dubboEndpoint::invoke); + // testHttpEndpoint("/dubbo", dubboQosEndpoints::invoke); testHttpEndpoint("/dubbo/configs", dubboConfigsMetadataEndpoint::configs); testHttpEndpoint("/dubbo/services", dubboServicesMetadataEndpoint::services); testHttpEndpoint("/dubbo/references", dubboReferencesMetadataEndpoint::references); @@ -235,7 +238,7 @@ void testHttpEndpoints() throws JsonProcessingException { private void testHttpEndpoint(String actuatorURI, Supplier resultsSupplier) throws JsonProcessingException { String actuatorURL = actuatorBaseURL + actuatorURI; String response = restTemplate.getForObject(actuatorURL, String.class); - Assert.assertEquals(objectMapper.writeValueAsString(resultsSupplier.get()), response); + assertEquals(objectMapper.writeValueAsString(resultsSupplier.get()), response); } interface DemoService { diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/test/java/org/apache/dubbo/spring/boot/actuate/health/DubboHealthIndicatorTest.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/actuate/health/DubboHealthIndicatorTest.java similarity index 71% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/test/java/org/apache/dubbo/spring/boot/actuate/health/DubboHealthIndicatorTest.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/actuate/health/DubboHealthIndicatorTest.java index c785cf8ac45..3509ebde1cf 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/test/java/org/apache/dubbo/spring/boot/actuate/health/DubboHealthIndicatorTest.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/actuate/health/DubboHealthIndicatorTest.java @@ -20,16 +20,17 @@ import java.util.Map; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.Status; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import static org.junit.jupiter.api.Assertions.assertEquals; /** * {@link DubboHealthIndicator} Test @@ -37,7 +38,7 @@ * @see DubboHealthIndicator * @since 2.7.0 */ -@RunWith(SpringRunner.class) +@ExtendWith(SpringExtension.class) @TestPropertySource( properties = { "dubbo.application.id = my-application-1", @@ -54,30 +55,30 @@ @SpringBootTest(classes = {DubboHealthIndicator.class, DubboHealthIndicatorTest.class}) @EnableConfigurationProperties(DubboHealthIndicatorProperties.class) @EnableDubboConfig -public class DubboHealthIndicatorTest { +class DubboHealthIndicatorTest { @Autowired private DubboHealthIndicator dubboHealthIndicator; @Test - public void testResolveStatusCheckerNamesMap() { + void testResolveStatusCheckerNamesMap() { Map statusCheckerNamesMap = dubboHealthIndicator.resolveStatusCheckerNamesMap(); - Assert.assertEquals(5, statusCheckerNamesMap.size()); + assertEquals(5, statusCheckerNamesMap.size()); - Assert.assertEquals("dubbo-protocol@ProtocolConfig.getStatus()", statusCheckerNamesMap.get("registry")); - Assert.assertEquals("dubbo-provider@ProviderConfig.getStatus()", statusCheckerNamesMap.get("server")); - Assert.assertEquals("management.health.dubbo.status.defaults", statusCheckerNamesMap.get("memory")); - Assert.assertEquals("management.health.dubbo.status.extras", statusCheckerNamesMap.get("load")); - Assert.assertEquals("management.health.dubbo.status.extras", statusCheckerNamesMap.get("threadpool")); + assertEquals("dubbo-protocol@ProtocolConfig.getStatus()", statusCheckerNamesMap.get("registry")); + assertEquals("dubbo-provider@ProviderConfig.getStatus()", statusCheckerNamesMap.get("server")); + assertEquals("management.health.dubbo.status.defaults", statusCheckerNamesMap.get("memory")); + assertEquals("management.health.dubbo.status.extras", statusCheckerNamesMap.get("load")); + assertEquals("management.health.dubbo.status.extras", statusCheckerNamesMap.get("threadpool")); } @Test - public void testHealth() { + void testHealth() { Health health = dubboHealthIndicator.health(); - Assert.assertEquals(Status.UNKNOWN, health.getStatus()); + assertEquals(Status.UNKNOWN, health.getStatus()); } } diff --git a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/test/resources/log4j2-test.xml b/dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/test/resources/log4j2-test.xml similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-actuator/src/test/resources/log4j2-test.xml rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure/src/test/resources/log4j2-test.xml diff --git a/dubbo-spring-boot/dubbo-spring-boot-actuator/JMX_HealthEndpoint.png b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/JMX_HealthEndpoint.png similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-actuator/JMX_HealthEndpoint.png rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/JMX_HealthEndpoint.png diff --git a/dubbo-spring-boot/dubbo-spring-boot-actuator/README.md b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/README.md similarity index 54% rename from dubbo-spring-boot/dubbo-spring-boot-actuator/README.md rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/README.md index b0f22c027ca..a753c9ef36b 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-actuator/README.md +++ b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/README.md @@ -153,7 +153,40 @@ Actuator endpoint `dubbo` supports Actuator Endpoints : | `dubboservices` | `false` | `/actuator/dubbo/services` | `GET` | Exposes all Dubbo's `ServiceBean` | `application/json` | | `dubboreferences` | `false` | `/actuator/dubbo/references` | `GET` | Exposes all Dubbo's `ReferenceBean` | `application/json` | | `dubboconfigs` | `true` | `/actuator/dubbo/configs` | `GET` | Exposes all Dubbo's `*Config` | `application/json` | -| `dubboshutdown` | `false` | `/actuator/dubbo/shutdown` | `POST` | Shutdown Dubbo services | `application/json` | +| `dubboshutdown` | `false` | `/actuator/dubbo/shutdown` | `GET` | Shutdown Dubbo services | `application/json` | +| `help` | `false` | `/actuator/dubbo/help` | `GET` | List all commands | | +| `ready` | `true` | `/actuator/dubbo/ready` | `GET` | Check whether the current process/service is ready for external service | `application/json` | +| `live` | `true` | `/actuator/dubbo/live` | `GET` | Check whether the current process/service is alive | `application/json` | +| `ls` | `false` | `/actuator/dubbo/ls` | `GET` | List consumers and providers | `application/json` | +| `startup` | `true` | `/actuator/dubbo/startup` | `GET` | Check if the current framework has been started | `application/json` | +| `ps` | `false` | `/actuator/dubbo/ps` | `GET` | View information about the current process, including `listenable` ports | `application/json` | +| `version` | `false` | `/actuator/dubbo/version` | `GET` | Display the version number of the currently running `Dubbo` | `application/json` | +| `getaddress` | `false` | `/actuator/dubbo/getaddress?args=xxx.*` | `GET` | View the list of valid `IP` addresses for a service | `application/json` | +| `getconfig` | `false` | `/actuator/dubbo/getconfig` | `GET` | View the valid `configuration` of the current application | `application/json` | +| `metrics` | `false` | `/actuator/dubbo/metrics` | `GET` | View `metrics`(Need to enable metrics statistics) | `application/json` | +| `metrics_default` | `false` | `/actuator/dubbo/metrics_default` | `GET` | View the default `metrics`(Need to enable metrics statistics) | `application/json` | +| `publishmetadata` | `false` | `/actuator/dubbo/publishmetadata` or `/actuator/dubbo/publishmetadata?args=10` | `GET` | Publishes or updates the current application `Metadata` (Delay can be set) | `application/json` | +| `online` | `false` | `/actuator/dubbo/online` or `/actuator/dubbo/online?args=xxx.*` | `GET` | Register one or more services to the registry (including application and interface addresses) | `application/json` | +| `onlineapp` | `false` | `/actuator/dubbo/onlineApp` or `/actuator/dubbo/onlineApp?args=xxx.xxx.*` | `GET` | Register one or more services to the registry (only application addresses) | `application/json` | +| `onlineinterface` | `false` | `/actuator/dubbo/onlineInterface` or `/actuator/dubbo/onlineInterface?args=xxx.*` | `GET` | Register one or more services to the registry (only interface addresses) | `application/json` | +| `offline` | `false` | `/actuator/dubbo/offline` or `/actuator/dubbo/offline?args=xxx.*` | `GET` | Unregister one or more services from the registry (including application and interface addresses) | `application/json` | +| `offlineapp` | `false` | `/actuator/dubbo/offlineApp` or `/actuator/dubbo/offlineApp?args=xxx.*` | `GET` | Unregister one or more services from the registry (only application addresses) | `application/json` | +| `offlineinterface` | `false` | `/actuator/dubbo/offlineInterface` or `/actuator/dubbo/offlineInterface?args=xxx.*` | `GET` | Unregister one or more services from the registry (only interface addresses) | `application/json` | +| `loggerinfo` | `false` | `/actuator/dubbo/loggerInfo` | `GET` | Query log configuration | `application/json` | +| `switchlogger` | `false` | `/actuator/dubbo/switchLogger?args={loggerAdapterName}` | `GET` | Modify the log output framework,`loggerAdapterName`: `slf4j`, `jcl`, `log4j`, `jdk`, `log4j2` | `application/json` | +| `switchloglevel` | `false` | `/actuator/dubbo/switchLogLevel?args={level}` | `GET` | Modify log level,level: `ALL`, `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `OFF` | `application/json` | +| `disabledetailprofiler` | `false` | `/actuator/dubbo/disableDetailProfiler` | `GET` | Turn off `detail profiler` mode, it will not affect `simple profiler` | `application/json` | +| `enabledetailprofiler` | `false` | `/actuator/dubbo/enableDetailProfiler` | `GET` | Enable the `detail profiler` mode, which is disabled by default, you need to enable the `simple profiler` mode to actually enable it | `application/json` | +| `disablesimpleprofiler` | `false` | `/actuator/dubbo/disableSimpleProfiler` | `GET` | Turn off the `simple profiler` mode, and the `detail profiler` will not be enabled after it is turned off | `application/json` | +| `enablesimpleprofiler` | `false` | `/actuator/dubbo/enableSimpleProfiler` | `GET` | Enable `simple profiler` mode, enabled by default | `application/json` | +| `setprofilerwarnpercent` | `false` | `/actuator/dubbo/setProfilerWarnPercent?args={percent}` | `GET` | Control `serialization` alarm frequency (only for classes in the warning list) | `application/json` | +| `serializecheckstatus` | `false` | `/actuator/dubbo/dubboserializecheckstatus` | `GET` | View the current configuration information | `application/json` | +| `serializewarnedclasses` | `false` | `/actuator/dubbo/dubboserializewarnedclasses` | `GET` | View the real-time alarm list | `application/json` | +| `disableroutersnapshot` | `false` | `/actuator/dubbo/disableRouterSnapshot` or `/actuator/dubbo/disableRouterSnapshot?args=xxx.*` | `GET` | Disable routing result collection mode | `application/json` | +| `enableroutersnapshot` | `false` | `/actuator/dubbo/enableRouterSnapshot` or `/actuator/dubbo/enableRouterSnapshot?args=xxx.*` | `GET` | Enable routing result collection mode | `application/json` | +| `getrecentroutersnapshot` | `false` | `/actuator/dubbo/getRecentRouterSnapshot` | `GET` | Obtain the historical routing status (up to 32 results stored) | `application/json` | +| `getenabledroutersnapshot` | `false` | `/actuator/dubbo/getEnabledRouterSnapshot` | `GET` | Get the services that are currently collecting | `application/json` | +| `gracefulshutdown` | `false` | `/actuator/dubbo/gracefulShutdown` | `GET` | Unregister all services registered by the current IP instance from the registry | `application/json` | @@ -429,6 +462,57 @@ The key is the simple name of Dubbo `*Config` Class , the value is`*Config` Bea +`/actuator/dubbo/ls `List consumers and providers : + +``` +As Provider side: ++-----------------------------------------------------------------------------------+-----------------------------+ +| Provider Service Name | PUB | ++-----------------------------------------------------------------------------------+-----------------------------+ +| DubboInternal - dubbo-springboot-demo-provider/org.apache.dubbo.metadata.MetadataService: 1.0.0 | | ++-----------------------------------------------------------------------------------+-----------------------------+ +|DubboInternal - dubbo-springboot-demo-provider/org.apache.dubbo.metrics.service.MetricsService: 1.0.0| | ++-----------------------------------------------------------------------------------+-----------------------------+ +| org.apache.dubbo.springboot.demo.DemoService |zookeeper-A(Y)/zookeeper-I(Y)| ++-----------------------------------------------------------------------------------+-----------------------------+ +As Consumer side: ++---------------------+---+ +|Consumer Service Name|NUM| ++---------------------+---+ + +``` + +- Services prefixed with `DubboInternal` are built-in services of Dubbo, and are not registered with the registry by default. + +- The first part of `zookeeper-A(Y)` in the service publishing status is the corresponding registry name, and the second part is the registration mode (`A` stands for application-level address registration, `I` stands for interface-level address registration), The third part represents whether the corresponding mode has been registered + +- The first part of `zookeeper-AF(I-2,A-2)` in the service subscription status is the corresponding registration center name, and the second part is the subscription mode (`AF` stands for dual subscription mode, `FA` stands for only Application-level subscription, `FI` stands for interface-level subscription only), the first half of the third part represents the source of the address mode (`A` stands for application-level address, `I` stands for interface-level address), and the second half represents the corresponding number of addresses + + + + +`/actuator/dubbo/switchLogLevel?args={level}` allows switching between permitted log levels, and the parameter cannot be empty, `/actuator/dubbo/switchLogLevel?args=WARN`. + +The log configuration modified by `switchLogger`/`switchLogLevel` is not stored persistently and will become invalid after the application is restarted. + + + +`/actuator/dubbo/disableSimpleProfiler` turn off the `simple profiler` mode, and the `detail profiler` will not be enabled after it is turned off. + +The performance sampling function can detect the time consumption of various parts of the Dubbo processing link,where `simple profiler` mode is enabled by default. + + + +`/actuator/dubbo/enableDetailProfiler` enable the `detail profiler` mode, which is disabled by default, you need to enable the `simple profiler` mode to actually enable it. + +Compared with the `simple profiler` mode, the `detail profiler` collects more time-consuming processing of each filter, specific time-consuming protocols, etc. In the `simple profiler` mode, if you find that there is a long time-consuming situation inside the Dubbo framework, you can enable the `detail profiler` mode to better troubleshoot the problem. + + + +`/actuator/dubbo/gracefulShutdown` unregister all services registered by the current IP instance from the registry. The difference from 'offline' is that this command will also notify all consumers via TCP connection to stop calling this instance. To restore, please execute 'online' to bring all services back online. + + + ## Externalized Configuration @@ -495,5 +579,38 @@ management.endpoint.dubboconfigs.enabled = true management.endpoint.dubboservices.enabled = true management.endpoint.dubboreferences.enabled = true management.endpoint.dubboproperties.enabled = true +management.endpoint.dubbo.help.enabled = true +management.endpoint.dubbo.ready.enabled = true +management.endpoint.dubbo.ls.enabled = true +management.endpoint.dubbo.live.enabled = true +management.endpoint.dubbo.startup.enabled = true +management.endpoint.dubbo.ps.enabled = true +management.endpoint.dubbo.version.enabled = true +management.endpoint.dubbo.getaddress.enabled = true +management.endpoint.dubbo.getconfig.enabled = true +management.endpoint.dubbo.metrics.enabled = true +management.endpoint.dubbo.metrics_default.enabled = true +management.endpoint.dubbo.publishmetadata.enabled = true +management.endpoint.dubbo.online.enabled = true +management.endpoint.dubbo.onlineapp.enabled = true +management.endpoint.dubbo.onlineinterface.enabled = true +management.endpoint.dubbo.offline.enabled = true +management.endpoint.dubbo.offlineapp.enabled = true +management.endpoint.dubbo.offlineinterface.enabled = true +management.endpoint.dubbo.loggerinfo.enabled = true +management.endpoint.dubbo.switchlogger.enabled = true +management.endpoint.dubbo.switchloglevel.enabled = true +management.endpoint.dubbo.disabledetailprofiler.enabled = true +management.endpoint.dubbo.disablesimpleprofiler.enabled = true +management.endpoint.dubbo.enabledetailprofiler.enabled = true +management.endpoint.dubbo.enablesimpleprofiler.enabled = true +management.endpoint.dubbo.setprofilerwarnpercent.enabled = true +management.endpoint.dubbo.serializecheckstatus.enabled = true +management.endpoint.dubbo.serializewarnedclasses.enabled = true +management.endpoint.dubbo.disableroutersnapshot.enabled = true +management.endpoint.dubbo.enableroutersnapshot.enabled = true +management.endpoint.dubbo.getrecentroutersnapshot.enabled = true +management.endpoint.dubbo.getenabledroutersnapshot.enabled = true +management.endpoint.dubbo.gracefulshutdown.enabled = true ``` diff --git a/dubbo-spring-boot/dubbo-spring-boot-actuator/pom.xml b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/pom.xml similarity index 90% rename from dubbo-spring-boot/dubbo-spring-boot-actuator/pom.xml rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/pom.xml index b91b00c5256..d579624b031 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-actuator/pom.xml +++ b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/pom.xml @@ -19,9 +19,9 @@ 4.0.0 org.apache.dubbo - dubbo-spring-boot + dubbo-parent ${revision} - ../pom.xml + ../../pom.xml dubbo-spring-boot-actuator @@ -30,12 +30,6 @@ - - org.apache.dubbo - dubbo-spring-boot-actuator-compatible - ${project.version} - - org.springframework.boot @@ -49,16 +43,9 @@ true - - org.springframework.boot - spring-boot-autoconfigure - true - - - org.apache.dubbo - dubbo-spring-boot-autoconfigure + dubbo-spring-boot ${project.version} @@ -111,6 +98,13 @@ true + + org.apache.dubbo + dubbo-qos + ${project.version} + true + + org.springframework.boot diff --git a/dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/GreeterWrapperServiceImpl.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboActuatorProperties.java similarity index 50% rename from dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/GreeterWrapperServiceImpl.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboActuatorProperties.java index 5fb68739f8d..a97e1ea7503 100644 --- a/dubbo-demo/dubbo-demo-triple/src/main/java/org/apache/dubbo/demo/GreeterWrapperServiceImpl.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboActuatorProperties.java @@ -14,16 +14,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.demo; +package org.apache.dubbo.spring.boot.actuate.endpoint; -public class GreeterWrapperServiceImpl implements GreeterWrapperService { +import java.util.Map; - @Override - public String sayHello(String request) { - StringBuilder responseBuilder = new StringBuilder(request); - for (int i = 0; i < 20; i++) { - responseBuilder.append(responseBuilder); +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +@Component +@ConfigurationProperties(prefix = "management.endpoint") +public class DubboActuatorProperties { + + private Map dubbo; + + public Map getDubbo() { + return dubbo; + } + + public void setDubbo(Map dubbo) { + this.dubbo = dubbo; + } + + public boolean isEnabled(String command) { + if (StringUtils.hasText(command)) { + Boolean enabled = dubbo.get(command + ".enabled"); + return enabled != null && enabled; + } else { + return false; } - return responseBuilder.toString(); } } diff --git a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboConfigsMetadataEndpoint.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboConfigsMetadataEndpoint.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboConfigsMetadataEndpoint.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboConfigsMetadataEndpoint.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboPropertiesMetadataEndpoint.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboPropertiesMetadataEndpoint.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboPropertiesMetadataEndpoint.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboPropertiesMetadataEndpoint.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboMetadataEndpoint.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboQosEndpoints.java similarity index 60% rename from dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboMetadataEndpoint.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboQosEndpoints.java index 3eb816d17af..1989365b8d1 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboMetadataEndpoint.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboQosEndpoints.java @@ -16,6 +16,8 @@ */ package org.apache.dubbo.spring.boot.actuate.endpoint; +import org.apache.dubbo.qos.command.ActuatorExecutor; +import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.spring.boot.actuate.endpoint.metadata.DubboMetadata; import java.util.Map; @@ -23,21 +25,40 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; import org.springframework.boot.actuate.endpoint.annotation.ReadOperation; +import org.springframework.boot.actuate.endpoint.annotation.Selector; +import org.springframework.lang.Nullable; /** - * Actuator {@link Endpoint} to expose Dubbo Meta Data + * Dubbo Actuator {@link Endpoint} * * @see Endpoint - * @since 2.7.0 + * @since 3.3.0 */ @Endpoint(id = "dubbo") -public class DubboMetadataEndpoint { +public class DubboQosEndpoints { + + @Autowired + private ApplicationModel applicationModel; @Autowired private DubboMetadata dubboMetadata; + @Autowired + private DubboActuatorProperties dubboActuatorProperties; + @ReadOperation public Map invoke() { return dubboMetadata.invoke(); } + + @ReadOperation + public String handleCommand(@Selector String command, @Nullable String[] args) { + if (dubboActuatorProperties.isEnabled(command.toLowerCase())) { + ActuatorExecutor actuatorExecutor = + applicationModel.getBeanFactory().getBean(ActuatorExecutor.class); + return actuatorExecutor.execute(command, args); + } else { + return ("Invalid command or not enabled"); + } + } } diff --git a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboReferencesMetadataEndpoint.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboReferencesMetadataEndpoint.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboReferencesMetadataEndpoint.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboReferencesMetadataEndpoint.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboServicesMetadataEndpoint.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboServicesMetadataEndpoint.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboServicesMetadataEndpoint.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboServicesMetadataEndpoint.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboShutdownEndpoint.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboShutdownEndpoint.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboShutdownEndpoint.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboShutdownEndpoint.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/condition/CompatibleConditionalOnEnabledEndpoint.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/condition/CompatibleConditionalOnEnabledEndpoint.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/condition/CompatibleConditionalOnEnabledEndpoint.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/condition/CompatibleConditionalOnEnabledEndpoint.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/condition/CompatibleOnEnabledEndpointCondition.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/condition/CompatibleOnEnabledEndpointCondition.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/condition/CompatibleOnEnabledEndpointCondition.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/condition/CompatibleOnEnabledEndpointCondition.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/AbstractDubboMetadata.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/AbstractDubboMetadata.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/AbstractDubboMetadata.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/AbstractDubboMetadata.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboConfigsMetadata.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboConfigsMetadata.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboConfigsMetadata.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboConfigsMetadata.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboMetadata.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboMetadata.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboMetadata.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboMetadata.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboPropertiesMetadata.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboPropertiesMetadata.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboPropertiesMetadata.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboPropertiesMetadata.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboReferencesMetadata.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboReferencesMetadata.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboReferencesMetadata.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboReferencesMetadata.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboServicesMetadata.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboServicesMetadata.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboServicesMetadata.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboServicesMetadata.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboShutdownMetadata.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboShutdownMetadata.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboShutdownMetadata.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/metadata/DubboShutdownMetadata.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/health/DubboHealthIndicator.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/health/DubboHealthIndicator.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/health/DubboHealthIndicator.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/health/DubboHealthIndicator.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/health/DubboHealthIndicatorProperties.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/health/DubboHealthIndicatorProperties.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/health/DubboHealthIndicatorProperties.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/health/DubboHealthIndicatorProperties.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/mertics/DubboMetricsBinder.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/mertics/DubboMetricsBinder.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/mertics/DubboMetricsBinder.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/mertics/DubboMetricsBinder.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/resources/META-INF/dubbo-endpoints-default.properties b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/resources/META-INF/dubbo-endpoints-default.properties similarity index 74% rename from dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/resources/META-INF/dubbo-endpoints-default.properties rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/resources/META-INF/dubbo-endpoints-default.properties index 2eef0739c0e..36078408ea9 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/resources/META-INF/dubbo-endpoints-default.properties +++ b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/main/resources/META-INF/dubbo-endpoints-default.properties @@ -2,20 +2,19 @@ # those values of properties can be override by higher PropertySource # @see DubboEndpointsAutoConfiguration -# Set enabled for Dubbo Endpoints -management.endpoint.dubbo.enabled = true -management.endpoint.dubboshutdown.enabled = false -management.endpoint.dubboconfigs.enabled = true -management.endpoint.dubboservices.enabled = false -management.endpoint.dubboreferences.enabled = false -management.endpoint.dubboproperties.enabled = true - # "management.endpoints.web.base-path" should not be configured in this file - # Re-defines path-mapping of Dubbo Web Endpoints - management.endpoints.web.path-mapping.dubboshutdown = dubbo/shutdown management.endpoints.web.path-mapping.dubboconfigs = dubbo/configs management.endpoints.web.path-mapping.dubboservices = dubbo/services management.endpoints.web.path-mapping.dubboreferences = dubbo/references management.endpoints.web.path-mapping.dubboproperties = dubbo/properties + +# Set endpoint enablement to be opt-in rather than opt-out +management.endpoints.enabled-by-default = false + +# Set enabled for Dubbo Endpoints +management.endpoint.dubbo.enabled = true +management.endpoint.dubbo.ready.enabled = true +management.endpoint.dubbo.startup.enabled = true +management.endpoint.dubbo.live.enabled = true diff --git a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/test/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboEndpointTest.java b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/test/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboEndpointTest.java similarity index 64% rename from dubbo-spring-boot/dubbo-spring-boot-actuator/src/test/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboEndpointTest.java rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/test/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboEndpointTest.java index 0aea4fc7a80..c623eb7802d 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/test/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboEndpointTest.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/test/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboEndpointTest.java @@ -21,7 +21,6 @@ import java.util.Map; -import org.junit.Assert; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -32,22 +31,25 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import static org.apache.dubbo.common.Version.getVersion; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; /** - * {@link DubboMetadataEndpoint} Test + * {@link DubboQosEndpoints} Test * - * @see DubboMetadataEndpoint + * @see DubboQosEndpoints * @since 2.7.0 */ @ExtendWith(SpringExtension.class) @SpringBootTest( - classes = {DubboMetadataEndpoint.class}, + classes = {DubboQosEndpoints.class}, properties = {"dubbo.application.name = dubbo-demo-application"}) @EnableAutoConfiguration class DubboEndpointTest { @Autowired - private DubboMetadataEndpoint dubboEndpoint; + private DubboQosEndpoints dubboQosEndpoints; @BeforeEach public void init() { @@ -62,23 +64,23 @@ public void destroy() { @Test void testInvoke() { - Map metadata = dubboEndpoint.invoke(); + Map metadata = dubboQosEndpoints.invoke(); - Assert.assertNotNull(metadata.get("timestamp")); + assertNotNull(metadata.get("timestamp")); Map versions = (Map) metadata.get("versions"); Map urls = (Map) metadata.get("urls"); - Assert.assertFalse(versions.isEmpty()); - Assert.assertFalse(urls.isEmpty()); + assertFalse(versions.isEmpty()); + assertFalse(urls.isEmpty()); - Assert.assertEquals(getVersion(DubboUtils.class, "1.0.0"), versions.get("dubbo-spring-boot")); - Assert.assertEquals(getVersion(), versions.get("dubbo")); + assertEquals(getVersion(DubboUtils.class, "1.0.0"), versions.get("dubbo-spring-boot")); + assertEquals(getVersion(), versions.get("dubbo")); - Assert.assertEquals("https://github.com/apache/dubbo", urls.get("dubbo")); - Assert.assertEquals("dev@dubbo.apache.org", urls.get("mailing-list")); - Assert.assertEquals("https://github.com/apache/dubbo-spring-boot-project", urls.get("github")); - Assert.assertEquals("https://github.com/apache/dubbo-spring-boot-project/issues", urls.get("issues")); - Assert.assertEquals("https://github.com/apache/dubbo-spring-boot-project.git", urls.get("git")); + assertEquals("https://github.com/apache/dubbo", urls.get("dubbo")); + assertEquals("dev@dubbo.apache.org", urls.get("mailing-list")); + assertEquals("https://github.com/apache/dubbo-spring-boot-project", urls.get("github")); + assertEquals("https://github.com/apache/dubbo-spring-boot-project/issues", urls.get("issues")); + assertEquals("https://github.com/apache/dubbo-spring-boot-project.git", urls.get("git")); } } diff --git a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/test/resources/log4j2-test.xml b/dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/test/resources/log4j2-test.xml similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/test/resources/log4j2-test.xml rename to dubbo-spring-boot-project/dubbo-spring-boot-actuator/src/test/resources/log4j2-test.xml diff --git a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/README.md b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/README.md similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-autoconfigure/README.md rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/README.md diff --git a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/config-popup-window.png b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/config-popup-window.png similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-autoconfigure/config-popup-window.png rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/config-popup-window.png diff --git a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/mconfig-popup-window.png b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/mconfig-popup-window.png similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-autoconfigure/mconfig-popup-window.png rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/mconfig-popup-window.png diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/pom.xml b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/pom.xml similarity index 50% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/pom.xml rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/pom.xml index 79fca44df3a..45e6e4a3b68 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/pom.xml +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/pom.xml @@ -19,19 +19,28 @@ 4.0.0 org.apache.dubbo - dubbo-spring-boot-compatible + dubbo-parent ${revision} - ../pom.xml + ../../pom.xml - dubbo-spring-boot-autoconfigure-compatible - Apache Dubbo Spring Boot Compatible for Spring Boot 1.x Auto-Configure + dubbo-spring-boot-autoconfigure + jar + Apache Dubbo Spring Boot Auto-Configure ${project.build.directory}/generated-sources/java + + + + org.apache.dubbo + dubbo-spring-boot-autoconfigure-compatible + ${project.version} + + org.springframework.boot @@ -41,16 +50,24 @@ org.springframework.boot - spring-boot + spring-boot-starter-log4j2 true + org.springframework.boot - spring-boot-starter-log4j2 + spring-boot-configuration-processor true + + + org.apache.dubbo + dubbo + ${project.version} + + org.apache.dubbo dubbo-common @@ -60,20 +77,143 @@ org.apache.dubbo - dubbo-config-spring + dubbo-triple-servlet ${project.version} true org.apache.dubbo - dubbo + dubbo-triple-websocket ${project.version} + true - org.springframework.boot - spring-boot-configuration-processor + javax.servlet + javax.servlet-api + provided + + + org.apache.tomcat.embed + tomcat-embed-core + provided + + + + jakarta.websocket + jakarta.websocket-api + provided + + + + jakarta.websocket + jakarta.websocket-client-api + provided + + + + + io.micrometer + micrometer-tracing + provided + + + io.micrometer + micrometer-observation + provided + + + io.micrometer + micrometer-core + provided + + + io.micrometer + micrometer-registry-prometheus-simpleclient + provided + + + io.micrometer + micrometer-core + + + + + com.tdunning + t-digest + provided + + + + + io.prometheus + simpleclient + provided + + + io.prometheus + simpleclient_pushgateway + provided + + + + org.springframework + spring-webmvc + true + + + org.springframework + spring-webflux + true + + + + + io.micrometer + micrometer-tracing-bridge-otel + true + + + io.micrometer + micrometer-tracing-bridge-brave + true + + + + + io.opentelemetry + opentelemetry-exporter-zipkin + true + + + io.opentelemetry + opentelemetry-exporter-otlp + true + + + io.zipkin.reporter2 + zipkin-reporter-brave + true + + + + + io.zipkin.reporter2 + zipkin-sender-urlconnection + true + + + + org.apache.dubbo + dubbo-qos + ${project.version} + true + + + org.apache.dubbo + dubbo-config-spring + ${project.version} true @@ -83,6 +223,28 @@ spring-boot-starter-test test + + + net.bytebuddy + byte-buddy + test + + + net.bytebuddy + byte-buddy-agent + test + + + org.apache.dubbo + dubbo-test-check + ${project.parent.version} + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + @@ -101,7 +263,7 @@ - + diff --git a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/BinderDubboConfigBinder.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/BinderDubboConfigBinder.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/BinderDubboConfigBinder.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/BinderDubboConfigBinder.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboAutoConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboAutoConfiguration.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboAutoConfiguration.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboAutoConfiguration.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboConfigurationProperties.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboConfigurationProperties.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboConfigurationProperties.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboConfigurationProperties.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboListenerAutoConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboListenerAutoConfiguration.java similarity index 83% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboListenerAutoConfiguration.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboListenerAutoConfiguration.java index f55a7ce72e9..7371aad446a 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboListenerAutoConfiguration.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboListenerAutoConfiguration.java @@ -16,8 +16,10 @@ */ package org.apache.dubbo.spring.boot.autoconfigure; +import org.apache.dubbo.rpc.Constants; import org.apache.dubbo.spring.boot.context.event.AwaitingNonWebApplicationListener; import org.apache.dubbo.spring.boot.context.event.DubboConfigBeanDefinitionConflictApplicationListener; +import org.apache.dubbo.spring.boot.context.event.DubboOpenAPIExportListener; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -46,4 +48,11 @@ public DubboConfigBeanDefinitionConflictApplicationListener dubboConfigBeanDefin public AwaitingNonWebApplicationListener awaitingNonWebApplicationListener() { return new AwaitingNonWebApplicationListener(); } + + @ConditionalOnMissingBean + @Bean + @ConditionalOnProperty(prefix = Constants.H2_SETTINGS_OPENAPI_PREFIX, name = "enabled", havingValue = "true") + public DubboOpenAPIExportListener dubboOpenAPIExportListener() { + return new DubboOpenAPIExportListener(); + } } diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboMetadataGenerateAutoConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboMetadataGenerateAutoConfiguration.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboMetadataGenerateAutoConfiguration.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboMetadataGenerateAutoConfiguration.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboRelaxedBinding2AutoConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboRelaxedBinding2AutoConfiguration.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboRelaxedBinding2AutoConfiguration.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboRelaxedBinding2AutoConfiguration.java diff --git a/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboTripleAutoConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboTripleAutoConfiguration.java new file mode 100644 index 00000000000..c238865a0ff --- /dev/null +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboTripleAutoConfiguration.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.dubbo.spring.boot.autoconfigure; + +import org.apache.dubbo.rpc.protocol.tri.ServletExchanger; +import org.apache.dubbo.rpc.protocol.tri.servlet.TripleFilter; +import org.apache.dubbo.rpc.protocol.tri.websocket.TripleWebSocketFilter; + +import javax.servlet.Filter; + +import org.apache.coyote.ProtocolHandler; +import org.apache.coyote.UpgradeProtocol; +import org.apache.coyote.http2.Http2Protocol; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; +import org.springframework.boot.web.embedded.tomcat.ConfigurableTomcatWebServerFactory; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +@Conditional(SpringBoot12Condition.class) +public class DubboTripleAutoConfiguration { + + public static final String SERVLET_PREFIX = "dubbo.protocol.triple.servlet"; + + public static final String WEBSOCKET_PREFIX = "dubbo.protocol.triple.websocket"; + + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(Filter.class) + @ConditionalOnWebApplication(type = Type.SERVLET) + @ConditionalOnProperty(prefix = SERVLET_PREFIX, name = "enabled", havingValue = "true") + public static class TripleServletConfiguration { + + @Bean + public FilterRegistrationBean tripleProtocolFilter( + @Value("${" + SERVLET_PREFIX + ".filter-url-patterns:/*}") String[] urlPatterns, + @Value("${" + SERVLET_PREFIX + ".filter-order:-1000000}") int order, + @Value("${server.port:8080}") int serverPort) { + ServletExchanger.bindServerPort(serverPort); + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(new TripleFilter()); + registrationBean.addUrlPatterns(urlPatterns); + registrationBean.setOrder(order); + return registrationBean; + } + + @Bean + @ConditionalOnClass(Http2Protocol.class) + @ConditionalOnProperty(prefix = SERVLET_PREFIX, name = "max-concurrent-streams") + public WebServerFactoryCustomizer tripleTomcatHttp2Customizer( + @Value("${" + SERVLET_PREFIX + ".max-concurrent-streams}") int maxConcurrentStreams) { + return factory -> factory.addConnectorCustomizers(connector -> { + ProtocolHandler handler = connector.getProtocolHandler(); + for (UpgradeProtocol upgradeProtocol : handler.findUpgradeProtocols()) { + if (upgradeProtocol instanceof Http2Protocol) { + Http2Protocol protocol = (Http2Protocol) upgradeProtocol; + int value = maxConcurrentStreams <= 0 ? Integer.MAX_VALUE : maxConcurrentStreams; + protocol.setMaxConcurrentStreams(value); + protocol.setMaxConcurrentStreamExecution(value); + } + } + }); + } + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(Filter.class) + @ConditionalOnWebApplication(type = Type.SERVLET) + @ConditionalOnProperty(prefix = WEBSOCKET_PREFIX, name = "enabled", havingValue = "true") + public static class TripleWebSocketConfiguration { + + @Bean + public FilterRegistrationBean tripleWebSocketFilter( + @Value("${" + WEBSOCKET_PREFIX + ".filter-url-patterns:/*}") String[] urlPatterns, + @Value("${" + WEBSOCKET_PREFIX + ".filter-order:-1000000}") int order, + @Value("${server.port:8080}") int serverPort) { + ServletExchanger.bindServerPort(serverPort); + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(new TripleWebSocketFilter()); + registrationBean.addUrlPatterns(urlPatterns); + registrationBean.setOrder(order); + return registrationBean; + } + } +} diff --git a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/SpringBoot12Condition.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/SpringBoot12Condition.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/SpringBoot12Condition.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/SpringBoot12Condition.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboMicrometerTracingAutoConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/DubboMicrometerTracingAutoConfiguration.java similarity index 83% rename from dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboMicrometerTracingAutoConfiguration.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/DubboMicrometerTracingAutoConfiguration.java index 8ec987dabf9..cc0c8de9567 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboMicrometerTracingAutoConfiguration.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/DubboMicrometerTracingAutoConfiguration.java @@ -14,13 +14,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.spring.boot.observability.autoconfigure; +package org.apache.dubbo.spring.boot.autoconfigure.observability; import org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration; -import org.apache.dubbo.spring.boot.observability.autoconfigure.annotation.ConditionalOnDubboTracingEnable; +import org.apache.dubbo.spring.boot.autoconfigure.observability.annotation.ConditionalOnDubboTracingEnable; import org.apache.dubbo.tracing.handler.DubboClientTracingObservationHandler; import org.apache.dubbo.tracing.handler.DubboServerTracingObservationHandler; +import io.micrometer.tracing.Tracer; +import io.micrometer.tracing.handler.PropagatingReceiverTracingObservationHandler; +import io.micrometer.tracing.handler.PropagatingSenderTracingObservationHandler; +import io.micrometer.tracing.propagation.Propagator; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -72,20 +76,18 @@ public io.micrometer.tracing.handler.DefaultTracingObservationHandler defaultTra @ConditionalOnMissingBean @ConditionalOnBean({io.micrometer.tracing.Tracer.class, io.micrometer.tracing.propagation.Propagator.class}) @Order(SENDER_TRACING_OBSERVATION_HANDLER_ORDER) - public io.micrometer.tracing.handler.PropagatingSenderTracingObservationHandler - propagatingSenderTracingObservationHandler( - io.micrometer.tracing.Tracer tracer, io.micrometer.tracing.propagation.Propagator propagator) { - return new io.micrometer.tracing.handler.PropagatingSenderTracingObservationHandler<>(tracer, propagator); + public PropagatingSenderTracingObservationHandler propagatingSenderTracingObservationHandler( + Tracer tracer, Propagator propagator) { + return new PropagatingSenderTracingObservationHandler<>(tracer, propagator); } @Bean @ConditionalOnMissingBean @ConditionalOnBean({io.micrometer.tracing.Tracer.class, io.micrometer.tracing.propagation.Propagator.class}) @Order(RECEIVER_TRACING_OBSERVATION_HANDLER_ORDER) - public io.micrometer.tracing.handler.PropagatingReceiverTracingObservationHandler - propagatingReceiverTracingObservationHandler( - io.micrometer.tracing.Tracer tracer, io.micrometer.tracing.propagation.Propagator propagator) { - return new io.micrometer.tracing.handler.PropagatingReceiverTracingObservationHandler<>(tracer, propagator); + public PropagatingReceiverTracingObservationHandler propagatingReceiverTracingObservationHandler( + Tracer tracer, Propagator propagator) { + return new PropagatingReceiverTracingObservationHandler<>(tracer, propagator); } @Bean diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboObservationAutoConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/DubboObservationAutoConfiguration.java similarity index 81% rename from dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboObservationAutoConfiguration.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/DubboObservationAutoConfiguration.java index d7014b64a85..46f90c74d8d 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/DubboObservationAutoConfiguration.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/DubboObservationAutoConfiguration.java @@ -14,18 +14,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.spring.boot.observability.autoconfigure; +package org.apache.dubbo.spring.boot.autoconfigure.observability; import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.config.spring.context.event.DubboConfigInitEvent; import org.apache.dubbo.qos.protocol.QosProtocolWrapper; import org.apache.dubbo.rpc.model.ApplicationModel; -import org.apache.dubbo.spring.boot.observability.autoconfigure.annotation.ConditionalOnDubboTracingEnable; +import org.apache.dubbo.spring.boot.autoconfigure.observability.annotation.ConditionalOnDubboTracingEnable; import java.util.Arrays; import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.observation.DefaultMeterObservationHandler; +import io.micrometer.core.instrument.observation.MeterObservationHandler; +import io.micrometer.observation.Observation; +import io.micrometer.observation.ObservationRegistry; +import io.micrometer.tracing.Tracer; +import io.micrometer.tracing.handler.TracingAwareMeterObservationHandler; +import io.micrometer.tracing.handler.TracingObservationHandler; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; @@ -69,8 +76,8 @@ public DubboObservationAutoConfiguration(ApplicationModel applicationModel) { @Bean @ConditionalOnMissingBean @ConditionalOnClass(name = "io.micrometer.observation.ObservationRegistry") - io.micrometer.observation.ObservationRegistry observationRegistry() { - return io.micrometer.observation.ObservationRegistry.create(); + ObservationRegistry observationRegistry() { + return ObservationRegistry.create(); } @Bean @@ -118,8 +125,7 @@ static class OnlyMetricsConfiguration { @Bean @ConditionalOnClass(name = "io.micrometer.core.instrument.observation.MeterObservationHandler") ObservationHandlerGrouping metricsObservationHandlerGrouping() { - return new ObservationHandlerGrouping( - io.micrometer.core.instrument.observation.MeterObservationHandler.class); + return new ObservationHandlerGrouping(MeterObservationHandler.class); } } @@ -133,7 +139,7 @@ static class OnlyTracingConfiguration { @Bean @ConditionalOnClass(name = "io.micrometer.tracing.handler.TracingObservationHandler") ObservationHandlerGrouping tracingObservationHandlerGrouping() { - return new ObservationHandlerGrouping(io.micrometer.tracing.handler.TracingObservationHandler.class); + return new ObservationHandlerGrouping(TracingObservationHandler.class); } } @@ -150,15 +156,14 @@ static class MetricsWithTracingConfiguration { "io.micrometer.core.instrument.observation.MeterObservationHandler" }) ObservationHandlerGrouping metricsAndTracingObservationHandlerGrouping() { - return new ObservationHandlerGrouping(Arrays.asList( - io.micrometer.tracing.handler.TracingObservationHandler.class, - io.micrometer.core.instrument.observation.MeterObservationHandler.class)); + return new ObservationHandlerGrouping( + Arrays.asList(TracingObservationHandler.class, MeterObservationHandler.class)); } } @Configuration(proxyBeanMethods = false) @ConditionalOnBean(MeterRegistry.class) - @ConditionalOnMissingBean(io.micrometer.core.instrument.observation.MeterObservationHandler.class) + @ConditionalOnMissingBean(MeterObservationHandler.class) static class MeterObservationHandlerConfiguration { @ConditionalOnMissingBean(type = "io.micrometer.tracing.Tracer") @@ -167,9 +172,8 @@ static class OnlyMetricsMeterObservationHandlerConfiguration { @Bean @ConditionalOnClass(name = {"io.micrometer.core.instrument.observation.DefaultMeterObservationHandler"}) - io.micrometer.core.instrument.observation.DefaultMeterObservationHandler defaultMeterObservationHandler( - MeterRegistry meterRegistry) { - return new io.micrometer.core.instrument.observation.DefaultMeterObservationHandler(meterRegistry); + DefaultMeterObservationHandler defaultMeterObservationHandler(MeterRegistry meterRegistry) { + return new DefaultMeterObservationHandler(meterRegistry); } } @@ -181,15 +185,13 @@ static class TracingAndMetricsObservationHandlerConfiguration { @ConditionalOnClass( name = { "io.micrometer.tracing.handler.TracingAwareMeterObservationHandler", - "io.micrometer.tracing.Tracer" + "io.micrometer.tracing.Tracer", + "io.micrometer.core.instrument.MeterRegistry" }) - io.micrometer.tracing.handler.TracingAwareMeterObservationHandler< - io.micrometer.observation.Observation.Context> - tracingAwareMeterObservationHandler( - MeterRegistry meterRegistry, io.micrometer.tracing.Tracer tracer) { - io.micrometer.core.instrument.observation.DefaultMeterObservationHandler delegate = - new io.micrometer.core.instrument.observation.DefaultMeterObservationHandler(meterRegistry); - return new io.micrometer.tracing.handler.TracingAwareMeterObservationHandler<>(delegate, tracer); + TracingAwareMeterObservationHandler tracingAwareMeterObservationHandler( + MeterRegistry meterRegistry, Tracer tracer) { + DefaultMeterObservationHandler delegate = new DefaultMeterObservationHandler(meterRegistry); + return new TracingAwareMeterObservationHandler<>(delegate, tracer); } } } diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservabilityUtils.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/ObservabilityUtils.java similarity index 96% rename from dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservabilityUtils.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/ObservabilityUtils.java index c4298d879df..81f0540520f 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservabilityUtils.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/ObservabilityUtils.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.spring.boot.observability.autoconfigure; +package org.apache.dubbo.spring.boot.autoconfigure.observability; import static org.apache.dubbo.spring.boot.util.DubboUtils.DUBBO_PREFIX; import static org.apache.dubbo.spring.boot.util.DubboUtils.PROPERTY_NAME_SEPARATOR; diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationHandlerGrouping.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/ObservationHandlerGrouping.java similarity index 98% rename from dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationHandlerGrouping.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/ObservationHandlerGrouping.java index 4d848dbea89..5e856b2929e 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationHandlerGrouping.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/ObservationHandlerGrouping.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.spring.boot.observability.autoconfigure; +package org.apache.dubbo.spring.boot.autoconfigure.observability; import java.util.ArrayList; import java.util.Collections; diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationRegistryPostProcessor.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/ObservationRegistryPostProcessor.java similarity index 97% rename from dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationRegistryPostProcessor.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/ObservationRegistryPostProcessor.java index 13308276013..ea8619a6421 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/ObservationRegistryPostProcessor.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/ObservationRegistryPostProcessor.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.spring.boot.observability.autoconfigure; +package org.apache.dubbo.spring.boot.autoconfigure.observability; import java.util.List; import java.util.stream.Collectors; diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/annotation/ConditionalOnDubboTracingEnable.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/annotation/ConditionalOnDubboTracingEnable.java similarity index 92% rename from dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/annotation/ConditionalOnDubboTracingEnable.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/annotation/ConditionalOnDubboTracingEnable.java index b389de1abd3..d4faf4c4123 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/annotation/ConditionalOnDubboTracingEnable.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/annotation/ConditionalOnDubboTracingEnable.java @@ -14,9 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.spring.boot.observability.autoconfigure.annotation; +package org.apache.dubbo.spring.boot.autoconfigure.observability.annotation; -import org.apache.dubbo.spring.boot.observability.autoconfigure.ObservabilityUtils; +import org.apache.dubbo.spring.boot.autoconfigure.observability.ObservabilityUtils; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/brave/BraveAutoConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/brave/BraveAutoConfiguration.java similarity index 98% rename from dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/brave/BraveAutoConfiguration.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/brave/BraveAutoConfiguration.java index 074a9923387..3e9f0d6ea7c 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/brave/BraveAutoConfiguration.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/brave/BraveAutoConfiguration.java @@ -14,13 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.spring.boot.observability.autoconfigure.brave; +package org.apache.dubbo.spring.boot.autoconfigure.observability.brave; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.spring.boot.autoconfigure.DubboConfigurationProperties; -import org.apache.dubbo.spring.boot.observability.autoconfigure.DubboMicrometerTracingAutoConfiguration; -import org.apache.dubbo.spring.boot.observability.autoconfigure.ObservabilityUtils; -import org.apache.dubbo.spring.boot.observability.autoconfigure.annotation.ConditionalOnDubboTracingEnable; +import org.apache.dubbo.spring.boot.autoconfigure.observability.DubboMicrometerTracingAutoConfiguration; +import org.apache.dubbo.spring.boot.autoconfigure.observability.ObservabilityUtils; +import org.apache.dubbo.spring.boot.autoconfigure.observability.annotation.ConditionalOnDubboTracingEnable; import java.util.Collections; import java.util.List; diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/otel/OpenTelemetryAutoConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/otel/OpenTelemetryAutoConfiguration.java similarity index 97% rename from dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/otel/OpenTelemetryAutoConfiguration.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/otel/OpenTelemetryAutoConfiguration.java index 678b2e48e09..1a3c9728cba 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/otel/OpenTelemetryAutoConfiguration.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/otel/OpenTelemetryAutoConfiguration.java @@ -14,15 +14,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.spring.boot.observability.autoconfigure.otel; +package org.apache.dubbo.spring.boot.autoconfigure.observability.otel; import org.apache.dubbo.common.Version; import org.apache.dubbo.common.utils.ClassUtils; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.spring.boot.autoconfigure.DubboConfigurationProperties; -import org.apache.dubbo.spring.boot.observability.autoconfigure.DubboMicrometerTracingAutoConfiguration; -import org.apache.dubbo.spring.boot.observability.autoconfigure.ObservabilityUtils; -import org.apache.dubbo.spring.boot.observability.autoconfigure.annotation.ConditionalOnDubboTracingEnable; +import org.apache.dubbo.spring.boot.autoconfigure.observability.DubboMicrometerTracingAutoConfiguration; +import org.apache.dubbo.spring.boot.autoconfigure.observability.ObservabilityUtils; +import org.apache.dubbo.spring.boot.autoconfigure.observability.annotation.ConditionalOnDubboTracingEnable; import java.util.Collections; import java.util.List; @@ -228,6 +228,7 @@ static class BaggageConfiguration { name = "type", havingValue = "W3C", matchIfMissing = true) + @ConditionalOnClass(name = {"io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext"}) io.opentelemetry.context.propagation.TextMapPropagator w3cTextMapPropagatorWithBaggage( io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext otelCurrentTraceContext) { List remoteFields = diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/otlp/OtlpAutoConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/otlp/OtlpAutoConfiguration.java similarity index 91% rename from dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/otlp/OtlpAutoConfiguration.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/otlp/OtlpAutoConfiguration.java index c5b79a6bead..47298d6d098 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/otlp/OtlpAutoConfiguration.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/otlp/OtlpAutoConfiguration.java @@ -14,11 +14,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.otlp; +package org.apache.dubbo.spring.boot.autoconfigure.observability.otlp; import org.apache.dubbo.config.nested.ExporterConfig.OtlpConfig; import org.apache.dubbo.spring.boot.autoconfigure.DubboConfigurationProperties; -import org.apache.dubbo.spring.boot.observability.autoconfigure.annotation.ConditionalOnDubboTracingEnable; +import org.apache.dubbo.spring.boot.autoconfigure.observability.annotation.ConditionalOnDubboTracingEnable; import java.util.Map; @@ -34,7 +34,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import static org.apache.dubbo.spring.boot.observability.autoconfigure.ObservabilityUtils.DUBBO_TRACING_OTLP_CONFIG_PREFIX; +import static org.apache.dubbo.spring.boot.autoconfigure.observability.ObservabilityUtils.DUBBO_TRACING_OTLP_CONFIG_PREFIX; import static org.apache.dubbo.spring.boot.util.DubboUtils.DUBBO_PREFIX; /** diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/HttpSender.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/zipkin/HttpSender.java similarity index 98% rename from dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/HttpSender.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/zipkin/HttpSender.java index eca49c9349b..02371f45c94 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/HttpSender.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/zipkin/HttpSender.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin; +package org.apache.dubbo.spring.boot.autoconfigure.observability.zipkin; import java.io.ByteArrayOutputStream; import java.io.IOException; diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinAutoConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/zipkin/ZipkinAutoConfiguration.java similarity index 78% rename from dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinAutoConfiguration.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/zipkin/ZipkinAutoConfiguration.java index d4dfdf54fc7..a57ec6ebfca 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinAutoConfiguration.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/zipkin/ZipkinAutoConfiguration.java @@ -14,13 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin; +package org.apache.dubbo.spring.boot.autoconfigure.observability.zipkin; -import org.apache.dubbo.spring.boot.observability.autoconfigure.annotation.ConditionalOnDubboTracingEnable; -import org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin.ZipkinConfigurations.BraveConfiguration; -import org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin.ZipkinConfigurations.OpenTelemetryConfiguration; -import org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin.ZipkinConfigurations.ReporterConfiguration; -import org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin.ZipkinConfigurations.SenderConfiguration; +import org.apache.dubbo.spring.boot.autoconfigure.observability.annotation.ConditionalOnDubboTracingEnable; +import org.apache.dubbo.spring.boot.autoconfigure.observability.zipkin.ZipkinConfigurations.BraveConfiguration; +import org.apache.dubbo.spring.boot.autoconfigure.observability.zipkin.ZipkinConfigurations.OpenTelemetryConfiguration; +import org.apache.dubbo.spring.boot.autoconfigure.observability.zipkin.ZipkinConfigurations.ReporterConfiguration; +import org.apache.dubbo.spring.boot.autoconfigure.observability.zipkin.ZipkinConfigurations.SenderConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -35,7 +35,7 @@ import zipkin2.codec.SpanBytesEncoder; import zipkin2.reporter.Sender; -import static org.apache.dubbo.spring.boot.observability.autoconfigure.ObservabilityUtils.DUBBO_TRACING_ZIPKIN_CONFIG_PREFIX; +import static org.apache.dubbo.spring.boot.autoconfigure.observability.ObservabilityUtils.DUBBO_TRACING_ZIPKIN_CONFIG_PREFIX; import static org.apache.dubbo.spring.boot.util.DubboUtils.DUBBO_PREFIX; /** diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinConfigurations.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/zipkin/ZipkinConfigurations.java similarity index 94% rename from dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinConfigurations.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/zipkin/ZipkinConfigurations.java index fd50844d9a1..d4a5cf001c5 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinConfigurations.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/zipkin/ZipkinConfigurations.java @@ -14,12 +14,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin; +package org.apache.dubbo.spring.boot.autoconfigure.observability.zipkin; import org.apache.dubbo.config.nested.ExporterConfig; import org.apache.dubbo.spring.boot.autoconfigure.DubboConfigurationProperties; -import org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin.customizer.ZipkinRestTemplateBuilderCustomizer; -import org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin.customizer.ZipkinWebClientBuilderCustomizer; +import org.apache.dubbo.spring.boot.autoconfigure.observability.zipkin.customizer.ZipkinRestTemplateBuilderCustomizer; +import org.apache.dubbo.spring.boot.autoconfigure.observability.zipkin.customizer.ZipkinWebClientBuilderCustomizer; import java.util.concurrent.atomic.AtomicReference; @@ -44,7 +44,7 @@ import zipkin2.reporter.brave.ZipkinSpanHandler; import zipkin2.reporter.urlconnection.URLConnectionSender; -import static org.apache.dubbo.spring.boot.observability.autoconfigure.ObservabilityUtils.DUBBO_TRACING_ZIPKIN_CONFIG_PREFIX; +import static org.apache.dubbo.spring.boot.autoconfigure.observability.ObservabilityUtils.DUBBO_TRACING_ZIPKIN_CONFIG_PREFIX; /** * Configurations for Zipkin. Those are imported by {@link ZipkinAutoConfiguration}. diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinRestTemplateSender.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/zipkin/ZipkinRestTemplateSender.java similarity index 96% rename from dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinRestTemplateSender.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/zipkin/ZipkinRestTemplateSender.java index 4fda686dc53..66046b95bfe 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinRestTemplateSender.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/zipkin/ZipkinRestTemplateSender.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin; +package org.apache.dubbo.spring.boot.autoconfigure.observability.zipkin; import org.springframework.http.HttpEntity; import org.springframework.http.HttpMethod; diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinWebClientSender.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/zipkin/ZipkinWebClientSender.java similarity index 97% rename from dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinWebClientSender.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/zipkin/ZipkinWebClientSender.java index e2f9d2f2dd2..30adfed4fab 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/ZipkinWebClientSender.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/zipkin/ZipkinWebClientSender.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin; +package org.apache.dubbo.spring.boot.autoconfigure.observability.zipkin; import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/customizer/ZipkinRestTemplateBuilderCustomizer.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/zipkin/customizer/ZipkinRestTemplateBuilderCustomizer.java similarity index 93% rename from dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/customizer/ZipkinRestTemplateBuilderCustomizer.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/zipkin/customizer/ZipkinRestTemplateBuilderCustomizer.java index 52db70e5514..df1963838cc 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/customizer/ZipkinRestTemplateBuilderCustomizer.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/zipkin/customizer/ZipkinRestTemplateBuilderCustomizer.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin.customizer; +package org.apache.dubbo.spring.boot.autoconfigure.observability.zipkin.customizer; import org.springframework.boot.web.client.RestTemplateBuilder; diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/customizer/ZipkinWebClientBuilderCustomizer.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/zipkin/customizer/ZipkinWebClientBuilderCustomizer.java similarity index 93% rename from dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/customizer/ZipkinWebClientBuilderCustomizer.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/zipkin/customizer/ZipkinWebClientBuilderCustomizer.java index 243242d1283..2400ebd4437 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/observability/autoconfigure/exporter/zipkin/customizer/ZipkinWebClientBuilderCustomizer.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/observability/zipkin/customizer/ZipkinWebClientBuilderCustomizer.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin.customizer; +package org.apache.dubbo.spring.boot.autoconfigure.observability.zipkin.customizer; import org.springframework.web.reactive.function.client.WebClient; diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json diff --git a/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000000..f2b1e71949e --- /dev/null +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -0,0 +1,11 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration,\ +org.apache.dubbo.spring.boot.autoconfigure.DubboListenerAutoConfiguration,\ +org.apache.dubbo.spring.boot.autoconfigure.DubboRelaxedBinding2AutoConfiguration,\ +org.apache.dubbo.spring.boot.autoconfigure.DubboTripleAutoConfiguration,\ +org.apache.dubbo.spring.boot.autoconfigure.observability.otel.OpenTelemetryAutoConfiguration,\ +org.apache.dubbo.spring.boot.autoconfigure.observability.DubboMicrometerTracingAutoConfiguration,\ +org.apache.dubbo.spring.boot.autoconfigure.observability.DubboObservationAutoConfiguration,\ +org.apache.dubbo.spring.boot.autoconfigure.observability.brave.BraveAutoConfiguration,\ +org.apache.dubbo.spring.boot.autoconfigure.observability.zipkin.ZipkinAutoConfiguration,\ +org.apache.dubbo.spring.boot.autoconfigure.observability.otlp.OtlpAutoConfiguration diff --git a/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..4a8cf8b5191 --- /dev/null +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,10 @@ +org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration +org.apache.dubbo.spring.boot.autoconfigure.DubboListenerAutoConfiguration +org.apache.dubbo.spring.boot.autoconfigure.DubboRelaxedBinding2AutoConfiguration +org.apache.dubbo.spring.boot.autoconfigure.DubboTripleAutoConfiguration +org.apache.dubbo.spring.boot.autoconfigure.observability.otel.OpenTelemetryAutoConfiguration +org.apache.dubbo.spring.boot.autoconfigure.observability.DubboMicrometerTracingAutoConfiguration +org.apache.dubbo.spring.boot.autoconfigure.observability.DubboObservationAutoConfiguration +org.apache.dubbo.spring.boot.autoconfigure.observability.brave.BraveAutoConfiguration +org.apache.dubbo.spring.boot.autoconfigure.observability.zipkin.ZipkinAutoConfiguration +org.apache.dubbo.spring.boot.autoconfigure.observability.otlp.OtlpAutoConfiguration diff --git a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/BinderDubboConfigBinderTest.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/BinderDubboConfigBinderTest.java similarity index 83% rename from dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/BinderDubboConfigBinderTest.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/BinderDubboConfigBinderTest.java index a81a187d729..b12c37c6af4 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/BinderDubboConfigBinderTest.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/BinderDubboConfigBinderTest.java @@ -23,23 +23,23 @@ import java.util.Map; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; import static org.apache.dubbo.config.spring.util.PropertySourcesUtils.getSubProperties; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * {@link BinderDubboConfigBinder} Test * * @since 2.7.0 */ -@RunWith(SpringRunner.class) +@ExtendWith(SpringExtension.class) @TestPropertySource(locations = "classpath:/dubbo.properties") @ContextConfiguration(classes = BinderDubboConfigBinder.class) class BinderDubboConfigBinderTest { @@ -56,17 +56,17 @@ void testBinder() { ApplicationConfig applicationConfig = new ApplicationConfig(); Map properties = getSubProperties(environment.getPropertySources(), "dubbo.application"); dubboConfigBinder.bind(properties, true, true, applicationConfig); - Assert.assertEquals("hello", applicationConfig.getName()); - Assert.assertEquals("world", applicationConfig.getOwner()); + assertEquals("hello", applicationConfig.getName()); + assertEquals("world", applicationConfig.getOwner()); RegistryConfig registryConfig = new RegistryConfig(); properties = getSubProperties(environment.getPropertySources(), "dubbo.registry"); dubboConfigBinder.bind(properties, true, true, registryConfig); - Assert.assertEquals("10.20.153.17", registryConfig.getAddress()); + assertEquals("10.20.153.17", registryConfig.getAddress()); ProtocolConfig protocolConfig = new ProtocolConfig(); properties = getSubProperties(environment.getPropertySources(), "dubbo.protocol"); dubboConfigBinder.bind(properties, true, true, protocolConfig); - Assert.assertEquals(Integer.valueOf(20881), protocolConfig.getPort()); + assertEquals(Integer.valueOf(20881), protocolConfig.getPort()); } } diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/CompatibleDubboAutoConfigurationTest.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/CompatibleDubboAutoConfigurationTest.java similarity index 81% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/CompatibleDubboAutoConfigurationTest.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/CompatibleDubboAutoConfigurationTest.java index ced20cf1172..93c04b413ce 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/CompatibleDubboAutoConfigurationTest.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/CompatibleDubboAutoConfigurationTest.java @@ -20,28 +20,29 @@ import org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationPostProcessor; import org.apache.dubbo.config.spring.util.DubboBeanUtils; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.PropertySource; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import static org.junit.jupiter.api.Assertions.assertNotNull; /** * {@link DubboAutoConfiguration} Test * @see DubboAutoConfiguration */ -@RunWith(SpringRunner.class) +@ExtendWith(SpringExtension.class) @SpringBootTest( classes = {CompatibleDubboAutoConfigurationTest.class}, properties = {"dubbo.scan.base-packages = org.apache.dubbo.spring.boot.autoconfigure"}) @EnableAutoConfiguration @PropertySource(value = "classpath:/META-INF/dubbo.properties") -public class CompatibleDubboAutoConfigurationTest { +class CompatibleDubboAutoConfigurationTest { @Autowired private ObjectProvider serviceAnnotationPostProcessor; @@ -50,12 +51,12 @@ public class CompatibleDubboAutoConfigurationTest { private ApplicationContext applicationContext; @Test - public void testBeans() { - Assert.assertNotNull(serviceAnnotationPostProcessor); - Assert.assertNotNull(serviceAnnotationPostProcessor.getIfAvailable()); + void testBeans() { + assertNotNull(serviceAnnotationPostProcessor); + assertNotNull(serviceAnnotationPostProcessor.getIfAvailable()); ReferenceAnnotationBeanPostProcessor referenceAnnotationBeanPostProcessor = DubboBeanUtils.getReferenceAnnotationBeanPostProcessor(applicationContext); - Assert.assertNotNull(referenceAnnotationBeanPostProcessor); + assertNotNull(referenceAnnotationBeanPostProcessor); } } diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/CompatibleDubboAutoConfigurationTestWithoutProperties.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/CompatibleDubboAutoConfigurationTestWithoutProperties.java similarity index 76% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/CompatibleDubboAutoConfigurationTestWithoutProperties.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/CompatibleDubboAutoConfigurationTestWithoutProperties.java index 746b759c7c6..1aa78f7004c 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/CompatibleDubboAutoConfigurationTestWithoutProperties.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/CompatibleDubboAutoConfigurationTestWithoutProperties.java @@ -21,28 +21,30 @@ import org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationPostProcessor; import org.apache.dubbo.config.spring.util.DubboBeanUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.ApplicationContext; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; /** * {@link DubboAutoConfiguration} Test * * @see DubboAutoConfiguration */ -@RunWith(SpringRunner.class) +@ExtendWith(SpringExtension.class) @SpringBootTest( classes = CompatibleDubboAutoConfigurationTestWithoutProperties.class, properties = {"dubbo.application.name=demo"}) @EnableAutoConfiguration -public class CompatibleDubboAutoConfigurationTestWithoutProperties { +class CompatibleDubboAutoConfigurationTestWithoutProperties { @Autowired(required = false) private ServiceAnnotationPostProcessor serviceAnnotationPostProcessor; @@ -50,22 +52,22 @@ public class CompatibleDubboAutoConfigurationTestWithoutProperties { @Autowired private ApplicationContext applicationContext; - @Before - public void init() { + @BeforeEach + void init() { DubboBootstrap.reset(); } - @After - public void destroy() { + @AfterEach + void destroy() { DubboBootstrap.reset(); } @Test - public void testBeans() { - Assert.assertNull(serviceAnnotationPostProcessor); + void testBeans() { + assertNull(serviceAnnotationPostProcessor); ReferenceAnnotationBeanPostProcessor referenceAnnotationBeanPostProcessor = DubboBeanUtils.getReferenceAnnotationBeanPostProcessor(applicationContext); - Assert.assertNotNull(referenceAnnotationBeanPostProcessor); + assertNotNull(referenceAnnotationBeanPostProcessor); } } diff --git a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/DubboRelaxedBinding2AutoConfigurationTest.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/DubboRelaxedBinding2AutoConfigurationTest.java similarity index 90% rename from dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/DubboRelaxedBinding2AutoConfigurationTest.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/DubboRelaxedBinding2AutoConfigurationTest.java index 8faa1bbd1ab..0cc4dfe26bb 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/DubboRelaxedBinding2AutoConfigurationTest.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/DubboRelaxedBinding2AutoConfigurationTest.java @@ -24,8 +24,8 @@ import java.util.Map; import java.util.Set; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -34,19 +34,19 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.util.ClassUtils; import static org.apache.dubbo.spring.boot.util.DubboUtils.BASE_PACKAGES_BEAN_NAME; import static org.apache.dubbo.spring.boot.util.DubboUtils.RELAXED_DUBBO_CONFIG_BINDER_BEAN_NAME; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * {@link DubboRelaxedBinding2AutoConfiguration} Test */ -@RunWith(SpringRunner.class) +@ExtendWith(SpringExtension.class) @SpringBootTest( classes = DubboRelaxedBinding2AutoConfigurationTest.class, properties = {"dubbo.scan.basePackages = org.apache.dubbo.spring.boot.autoconfigure"}) diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/DubboAutoConfigurationOnMultipleConfigTest.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/base/DubboAutoConfigurationOnMultipleConfigTest.java similarity index 72% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/DubboAutoConfigurationOnMultipleConfigTest.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/base/DubboAutoConfigurationOnMultipleConfigTest.java index 4bbd80c618a..e5e2031c62e 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/DubboAutoConfigurationOnMultipleConfigTest.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/base/DubboAutoConfigurationOnMultipleConfigTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.spring.boot.autoconfigure; +package org.apache.dubbo.spring.boot.autoconfigure.base; import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.ConsumerConfig; @@ -24,26 +24,28 @@ import org.apache.dubbo.config.ProviderConfig; import org.apache.dubbo.config.RegistryConfig; import org.apache.dubbo.config.bootstrap.DubboBootstrap; +import org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.ComponentScan; import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import static org.junit.jupiter.api.Assertions.assertEquals; /** * {@link DubboAutoConfiguration} Test On multiple Dubbo Configuration * * @since 2.7.0 */ -@RunWith(SpringRunner.class) +@ExtendWith(SpringExtension.class) @TestPropertySource( properties = { "dubbo.applications.application1.name=dubbo-demo-multi-application", @@ -60,7 +62,7 @@ @SpringBootTest(classes = {DubboAutoConfigurationOnMultipleConfigTest.class}) @EnableAutoConfiguration @ComponentScan -public class DubboAutoConfigurationOnMultipleConfigTest { +class DubboAutoConfigurationOnMultipleConfigTest { /** * @see TestBeansConfiguration @@ -93,34 +95,34 @@ public class DubboAutoConfigurationOnMultipleConfigTest { @Qualifier("provider1") ProviderConfig provider; - @Before - public void init() { + @BeforeEach + void init() { DubboBootstrap.reset(); } - @After - public void destroy() { + @AfterEach + void destroy() { DubboBootstrap.reset(); } @Test - public void testMultiConfig() { + void testMultiConfig() { // application - Assert.assertEquals("dubbo-demo-multi-application", application.getName()); + assertEquals("dubbo-demo-multi-application", application.getName()); // module - Assert.assertEquals("dubbo-demo-module", module.getName()); + assertEquals("dubbo-demo-module", module.getName()); // registry - Assert.assertEquals("test://192.168.99.100:32770", registry.getAddress()); - Assert.assertEquals("test", registry.getProtocol()); - Assert.assertEquals(Integer.valueOf(32770), registry.getPort()); + assertEquals("test://192.168.99.100:32770", registry.getAddress()); + assertEquals("test", registry.getProtocol()); + assertEquals(Integer.valueOf(32770), registry.getPort()); // monitor - Assert.assertEquals("test://127.0.0.1:32770", monitor.getAddress()); + assertEquals("test://127.0.0.1:32770", monitor.getAddress()); // protocol - Assert.assertEquals("dubbo", protocol.getName()); - Assert.assertEquals(Integer.valueOf(20880), protocol.getPort()); + assertEquals("dubbo", protocol.getName()); + assertEquals(Integer.valueOf(20880), protocol.getPort()); // consumer - Assert.assertEquals("netty", consumer.getClient()); + assertEquals("netty", consumer.getClient()); // provider - Assert.assertEquals("127.0.0.1", provider.getHost()); + assertEquals("127.0.0.1", provider.getHost()); } } diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/DubboAutoConfigurationOnSingleConfigTest.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/base/DubboAutoConfigurationOnSingleConfigTest.java similarity index 70% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/DubboAutoConfigurationOnSingleConfigTest.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/base/DubboAutoConfigurationOnSingleConfigTest.java index 214b0cec7f9..fe8eb6149ff 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/DubboAutoConfigurationOnSingleConfigTest.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/base/DubboAutoConfigurationOnSingleConfigTest.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.spring.boot.autoconfigure; +package org.apache.dubbo.spring.boot.autoconfigure.base; import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.ConsumerConfig; @@ -24,25 +24,27 @@ import org.apache.dubbo.config.ProviderConfig; import org.apache.dubbo.config.RegistryConfig; import org.apache.dubbo.config.bootstrap.DubboBootstrap; +import org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.ComponentScan; import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import static org.junit.jupiter.api.Assertions.assertEquals; /** * {@link DubboAutoConfiguration} Test On single Dubbo Configuration * * @since 2.7.0 */ -@RunWith(SpringRunner.class) +@ExtendWith(SpringExtension.class) @TestPropertySource( properties = { "dubbo.application.name = dubbo-demo-single-application", @@ -57,7 +59,7 @@ @SpringBootTest(classes = {DubboAutoConfigurationOnSingleConfigTest.class}) @EnableAutoConfiguration @ComponentScan -public class DubboAutoConfigurationOnSingleConfigTest { +class DubboAutoConfigurationOnSingleConfigTest { @Autowired private ApplicationConfig applicationConfig; @@ -80,32 +82,32 @@ public class DubboAutoConfigurationOnSingleConfigTest { @Autowired private ProtocolConfig protocolConfig; - @Before - public void init() { + @BeforeEach + void init() { DubboBootstrap.reset(); } - @After - public void destroy() { + @AfterEach + void destroy() { DubboBootstrap.reset(); } @Test - public void testSingleConfig() { + void testSingleConfig() { // application - Assert.assertEquals("dubbo-demo-single-application", applicationConfig.getName()); + assertEquals("dubbo-demo-single-application", applicationConfig.getName()); // module - Assert.assertEquals("dubbo-demo-module", moduleConfig.getName()); + assertEquals("dubbo-demo-module", moduleConfig.getName()); // registry - Assert.assertEquals("test://192.168.99.100:32770", registryConfig.getAddress()); + assertEquals("test://192.168.99.100:32770", registryConfig.getAddress()); // monitor - Assert.assertEquals("test://127.0.0.1:32770", monitorConfig.getAddress()); + assertEquals("test://127.0.0.1:32770", monitorConfig.getAddress()); // protocol - Assert.assertEquals("dubbo", protocolConfig.getName()); - Assert.assertEquals(Integer.valueOf(20880), protocolConfig.getPort()); + assertEquals("dubbo", protocolConfig.getName()); + assertEquals(Integer.valueOf(20880), protocolConfig.getPort()); // consumer - Assert.assertEquals("netty", consumerConfig.getClient()); + assertEquals("netty", consumerConfig.getClient()); // provider - Assert.assertEquals("127.0.0.1", providerConfig.getHost()); + assertEquals("127.0.0.1", providerConfig.getHost()); } } diff --git a/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/base/TestBeansConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/base/TestBeansConfiguration.java new file mode 100644 index 00000000000..22d925fc211 --- /dev/null +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/base/TestBeansConfiguration.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.dubbo.spring.boot.autoconfigure.base; + +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ConsumerConfig; +import org.apache.dubbo.config.ModuleConfig; +import org.apache.dubbo.config.MonitorConfig; +import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.ProviderConfig; +import org.apache.dubbo.config.RegistryConfig; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class TestBeansConfiguration { + + @Bean + ApplicationConfig application1() { + ApplicationConfig config = new ApplicationConfig(); + config.setId("application1"); + return config; + } + + @Bean + ModuleConfig module1() { + ModuleConfig config = new ModuleConfig(); + config.setId("module1"); + return config; + } + + @Bean + RegistryConfig registry1() { + RegistryConfig config = new RegistryConfig(); + config.setId("registry1"); + return config; + } + + @Bean + MonitorConfig monitor1() { + MonitorConfig config = new MonitorConfig(); + config.setId("monitor1"); + return config; + } + + @Bean + ProtocolConfig protocol1() { + ProtocolConfig config = new ProtocolConfig(); + config.setId("protocol1"); + return config; + } + + @Bean + ConsumerConfig consumer1() { + ConsumerConfig config = new ConsumerConfig(); + config.setId("consumer1"); + return config; + } + + @Bean + ProviderConfig provider1() { + ProviderConfig config = new ProviderConfig(); + config.setId("provider1"); + return config; + } +} diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/observability/autoconfigure/observability/DubboMicrometerTracingAutoConfigurationTests.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/observability/DubboMicrometerTracingAutoConfigurationTests.java similarity index 97% rename from dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/observability/autoconfigure/observability/DubboMicrometerTracingAutoConfigurationTests.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/observability/DubboMicrometerTracingAutoConfigurationTests.java index 4b2f9e48686..372bef879db 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/observability/autoconfigure/observability/DubboMicrometerTracingAutoConfigurationTests.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/observability/DubboMicrometerTracingAutoConfigurationTests.java @@ -14,9 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.spring.boot.observability.autoconfigure.observability; - -import org.apache.dubbo.spring.boot.observability.autoconfigure.DubboMicrometerTracingAutoConfiguration; +package org.apache.dubbo.spring.boot.autoconfigure.observability; import java.util.List; import java.util.stream.Collectors; diff --git a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessorTest.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessorTest.java similarity index 82% rename from dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessorTest.java rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessorTest.java index cb9963777de..952e5aebb93 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessorTest.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessorTest.java @@ -18,8 +18,7 @@ import java.util.HashMap; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.springframework.boot.SpringApplication; import org.springframework.core.Ordered; import org.springframework.core.env.MapPropertySource; @@ -27,6 +26,9 @@ import org.springframework.core.env.PropertySource; import org.springframework.mock.env.MockEnvironment; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + /** * {@link DubboDefaultPropertiesEnvironmentPostProcessor} Test */ @@ -39,7 +41,7 @@ class DubboDefaultPropertiesEnvironmentPostProcessorTest { @Test void testOrder() { - Assert.assertEquals(Ordered.LOWEST_PRECEDENCE, instance.getOrder()); + assertEquals(Ordered.LOWEST_PRECEDENCE, instance.getOrder()); } @Test @@ -51,16 +53,16 @@ void testPostProcessEnvironment() { MutablePropertySources propertySources = environment.getPropertySources(); // Nothing to change PropertySource defaultPropertySource = propertySources.get("defaultProperties"); - Assert.assertNotNull(defaultPropertySource); - Assert.assertEquals("true", defaultPropertySource.getProperty("dubbo.config.multiple")); - Assert.assertEquals("true", defaultPropertySource.getProperty("dubbo.application.qos-enable")); + assertNotNull(defaultPropertySource); + assertEquals("true", defaultPropertySource.getProperty("dubbo.config.multiple")); + // assertEquals("true", defaultPropertySource.getProperty("dubbo.application.qos-enable")); // Case 2 : Only set property "spring.application.name" environment.setProperty("spring.application.name", "demo-dubbo-application"); instance.postProcessEnvironment(environment, springApplication); defaultPropertySource = propertySources.get("defaultProperties"); Object dubboApplicationName = defaultPropertySource.getProperty("dubbo.application.name"); - Assert.assertEquals("demo-dubbo-application", dubboApplicationName); + assertEquals("demo-dubbo-application", dubboApplicationName); // Case 3 : Only set property "dubbo.application.name" // Reset environment @@ -69,9 +71,9 @@ void testPostProcessEnvironment() { environment.setProperty("dubbo.application.name", "demo-dubbo-application"); instance.postProcessEnvironment(environment, springApplication); defaultPropertySource = propertySources.get("defaultProperties"); - Assert.assertNotNull(defaultPropertySource); + assertNotNull(defaultPropertySource); dubboApplicationName = environment.getProperty("dubbo.application.name"); - Assert.assertEquals("demo-dubbo-application", dubboApplicationName); + assertEquals("demo-dubbo-application", dubboApplicationName); // Case 4 : If "defaultProperties" PropertySource is present in PropertySources // Reset environment @@ -82,7 +84,7 @@ void testPostProcessEnvironment() { instance.postProcessEnvironment(environment, springApplication); defaultPropertySource = propertySources.get("defaultProperties"); dubboApplicationName = defaultPropertySource.getProperty("dubbo.application.name"); - Assert.assertEquals("demo-dubbo-application", dubboApplicationName); + assertEquals("demo-dubbo-application", dubboApplicationName); // Case 5 : Reset dubbo.config.multiple and dubbo.application.qos-enable environment = new MockEnvironment(); @@ -91,7 +93,7 @@ void testPostProcessEnvironment() { environment.setProperty("dubbo.config.multiple", "false"); environment.setProperty("dubbo.application.qos-enable", "false"); instance.postProcessEnvironment(environment, springApplication); - Assert.assertEquals("false", environment.getProperty("dubbo.config.multiple")); - Assert.assertEquals("false", environment.getProperty("dubbo.application.qos-enable")); + assertEquals("false", environment.getProperty("dubbo.config.multiple")); + assertEquals("false", environment.getProperty("dubbo.application.qos-enable")); } } diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/resources/META-INF/dubbo.properties b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/resources/META-INF/dubbo.properties similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/resources/META-INF/dubbo.properties rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/resources/META-INF/dubbo.properties diff --git a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/test/resources/dubbo.properties b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/resources/dubbo.properties similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/test/resources/dubbo.properties rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/resources/dubbo.properties diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/test/resources/log4j2-test.xml b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/resources/log4j2-test.xml similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/test/resources/log4j2-test.xml rename to dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/test/resources/log4j2-test.xml diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/pom.xml b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-actuator-autoconfigure-compatible/pom.xml similarity index 84% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/pom.xml rename to dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-actuator-autoconfigure-compatible/pom.xml index a185cbb07c9..f7b453f7f8a 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/pom.xml +++ b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-actuator-autoconfigure-compatible/pom.xml @@ -24,8 +24,8 @@ ../pom.xml - dubbo-spring-boot-actuator-compatible - Apache Dubbo Spring Boot Compatible for Spring Boot 1.x Actuator + dubbo-spring-boot-actuator-autoconfigure-compatible + Apache Dubbo Spring Boot Actuator Autoconfigure Compatible for Spring Boot 1.x Actuator @@ -47,6 +47,12 @@ true + + org.apache.dubbo + dubbo-spring-boot-actuator + ${project.version} + + org.springframework.boot spring-boot-autoconfigure @@ -63,7 +69,7 @@ org.apache.dubbo - dubbo-spring-boot-autoconfigure-compatible + dubbo-spring-boot-autoconfigure ${project.version} @@ -94,6 +100,13 @@ test + + org.apache.dubbo + dubbo-qos + ${project.version} + true + + org.springframework.boot diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointAutoConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-actuator-autoconfigure-compatible/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointAutoConfiguration.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointAutoConfiguration.java rename to dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-actuator-autoconfigure-compatible/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointAutoConfiguration.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboMvcEndpointManagementContextConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-actuator-autoconfigure-compatible/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboMvcEndpointManagementContextConfiguration.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboMvcEndpointManagementContextConfiguration.java rename to dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-actuator-autoconfigure-compatible/src/main/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboMvcEndpointManagementContextConfiguration.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboEndpoint.java b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-actuator-autoconfigure-compatible/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboEndpoint.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboEndpoint.java rename to dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-actuator-autoconfigure-compatible/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/DubboEndpoint.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/mvc/DubboMvcEndpoint.java b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-actuator-autoconfigure-compatible/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/mvc/DubboMvcEndpoint.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/mvc/DubboMvcEndpoint.java rename to dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-actuator-autoconfigure-compatible/src/main/java/org/apache/dubbo/spring/boot/actuate/endpoint/mvc/DubboMvcEndpoint.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/resources/META-INF/spring.factories b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-actuator-autoconfigure-compatible/src/main/resources/META-INF/spring.factories similarity index 53% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/resources/META-INF/spring.factories rename to dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-actuator-autoconfigure-compatible/src/main/resources/META-INF/spring.factories index bea4633af23..4f0be089821 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/resources/META-INF/spring.factories +++ b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-actuator-autoconfigure-compatible/src/main/resources/META-INF/spring.factories @@ -1,6 +1,4 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -org.apache.dubbo.spring.boot.actuate.autoconfigure.DubboEndpointAutoConfiguration,\ -org.apache.dubbo.spring.boot.actuate.autoconfigure.DubboHealthIndicatorAutoConfiguration,\ -org.apache.dubbo.spring.boot.actuate.autoconfigure.DubboEndpointMetadataAutoConfiguration +org.apache.dubbo.spring.boot.actuate.autoconfigure.DubboEndpointAutoConfiguration org.springframework.boot.actuate.autoconfigure.ManagementContextConfiguration=\ -org.apache.dubbo.spring.boot.actuate.autoconfigure.DubboMvcEndpointManagementContextConfiguration \ No newline at end of file +org.apache.dubbo.spring.boot.actuate.autoconfigure.DubboMvcEndpointManagementContextConfiguration diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/resources/META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-actuator-autoconfigure-compatible/src/main/resources/META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/main/resources/META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports rename to dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-actuator-autoconfigure-compatible/src/main/resources/META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports diff --git a/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-actuator-autoconfigure-compatible/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-actuator-autoconfigure-compatible/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..b541384214e --- /dev/null +++ b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-actuator-autoconfigure-compatible/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.apache.dubbo.spring.boot.actuate.autoconfigure.DubboEndpointAutoConfiguration diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/test/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointAutoConfigurationTest.java b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-actuator-autoconfigure-compatible/src/test/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointAutoConfigurationTest.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/actuator/src/test/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointAutoConfigurationTest.java rename to dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-actuator-autoconfigure-compatible/src/test/java/org/apache/dubbo/spring/boot/actuate/autoconfigure/DubboEndpointAutoConfigurationTest.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/resources/log4j2-test.xml b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-actuator-autoconfigure-compatible/src/test/resources/log4j2-test.xml similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/resources/log4j2-test.xml rename to dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-actuator-autoconfigure-compatible/src/test/resources/log4j2-test.xml diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/README.md b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/README.md similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/README.md rename to dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/README.md diff --git a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/pom.xml b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/pom.xml similarity index 82% rename from dubbo-spring-boot/dubbo-spring-boot-autoconfigure/pom.xml rename to dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/pom.xml index 4d85060d466..455533ad504 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/pom.xml +++ b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/pom.xml @@ -19,28 +19,25 @@ 4.0.0 org.apache.dubbo - dubbo-spring-boot + dubbo-spring-boot-compatible ${revision} ../pom.xml - dubbo-spring-boot-autoconfigure - jar - Apache Dubbo Spring Boot Auto-Configure + dubbo-spring-boot-autoconfigure-compatible + Apache Dubbo Spring Boot Compatible for Spring Boot 1.x Auto-Configure - - + - org.apache.dubbo - dubbo-spring-boot-autoconfigure-compatible - ${project.version} + org.springframework.boot + spring-boot-autoconfigure + true - org.springframework.boot - spring-boot-autoconfigure + spring-boot true @@ -50,37 +47,35 @@ true - org.apache.dubbo - dubbo + dubbo-common ${project.version} + true org.apache.dubbo - dubbo-common + dubbo-config-spring ${project.version} true org.apache.dubbo - dubbo-config-spring + dubbo ${project.version} - true org.apache.dubbo - dubbo-triple-servlet + dubbo-spring-boot ${project.version} - true - javax.servlet - javax.servlet-api + javax.websocket + javax.websocket-api provided diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboRelaxedBindingAutoConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboRelaxedBindingAutoConfiguration.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboRelaxedBindingAutoConfiguration.java rename to dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboRelaxedBindingAutoConfiguration.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/RelaxedDubboConfigBinder.java b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/RelaxedDubboConfigBinder.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/RelaxedDubboConfigBinder.java rename to dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/RelaxedDubboConfigBinder.java diff --git a/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 00000000000..f095b721e47 --- /dev/null +++ b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,44 @@ +{ + "properties": [ + { + "name": "dubbo.enabled", + "description": "Whether enable autoconfiguration of dubbo, default value is true.", + "type": "java.util.Set" + }, + { + "name": "dubbo.labels", + "description": "The labels for these service providers, enabling categorization and grouping, thereby enhancing their management and monitoring, the multiple-value is delimited by ';'.", + "type": "java.lang.String" + }, + { + "name": "dubbo.env.keys", + "description": "The keys for specify environment-specific keys, allowing for differentiation and utilization of various runtime environments (e.g., development, testing, production), the multiple-value is delimited by comma.", + "type": "java.lang.String" + }, + { + "name": "dubbo.config.override", + "description": " Whether to allow configuration override in Dubbo, default value is true.", + "type": "java.lang.Boolean" + }, + { + "name": "dubbo.config.multiple", + "description": "Whether to enable multiple configurations in Dubbo, allowing multiple configurations to be loaded and used, default value is true.", + "type": "java.lang.Boolean" + }, + { + "name": "dubbo.config.mode", + "description": "Config processing mode. See org.apache.dubbo.config.context.ConfigMode.", + "type": "org.apache.dubbo.config.context.ConfigMode" + }, + { + "name": "dubbo.config-center.include-spring-env", + "description": "Whether to include Spring Environment.", + "type": "java.lang.Boolean" + }, + { + "name": "dubbo.scan.base-packages", + "description": "The basePackages to scan, the multiple-value is delimited by comma @see EnableDubbo#scanBasePackages().", + "type": "java.util.Set" + } + ] +} diff --git a/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/src/main/resources/META-INF/spring.factories b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000000..857b033ff63 --- /dev/null +++ b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +org.apache.dubbo.spring.boot.autoconfigure.DubboRelaxedBindingAutoConfiguration diff --git a/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..80ae6b412a9 --- /dev/null +++ b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.apache.dubbo.spring.boot.autoconfigure.DubboRelaxedBindingAutoConfiguration diff --git a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/rest/api/DubboServiceAnnotationService.java b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/src/test/java/org/apache/dubbo/spring/boot/TestSuite.java similarity index 73% rename from dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/rest/api/DubboServiceAnnotationService.java rename to dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/src/test/java/org/apache/dubbo/spring/boot/TestSuite.java index 478b3e6dc20..6e76c583280 100644 --- a/dubbo-demo/dubbo-demo-interface/src/main/java/org/apache/dubbo/demo/rest/api/DubboServiceAnnotationService.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/src/test/java/org/apache/dubbo/spring/boot/TestSuite.java @@ -14,15 +14,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.demo.rest.api; +package org.apache.dubbo.spring.boot; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.Path; +import org.apache.dubbo.spring.boot.autoconfigure.RelaxedDubboConfigBinderTest; -@Path("/annotation") -public interface DubboServiceAnnotationService { - @GET - @Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN}) - String annotation(); -} +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +@RunWith(Suite.class) +@Suite.SuiteClasses({ + RelaxedDubboConfigBinderTest.class, +}) +public class TestSuite {} diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/RelaxedDubboConfigBinderTest.java b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/RelaxedDubboConfigBinderTest.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/RelaxedDubboConfigBinderTest.java rename to dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/RelaxedDubboConfigBinderTest.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/TestBeansConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/TestBeansConfiguration.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/TestBeansConfiguration.java rename to dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/src/test/java/org/apache/dubbo/spring/boot/autoconfigure/TestBeansConfiguration.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/test/resources/log4j2-test.xml b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/src/test/resources/log4j2-test.xml similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/test/resources/log4j2-test.xml rename to dubbo-spring-boot-project/dubbo-spring-boot-compatible/dubbo-spring-boot-autoconfigure-compatible/src/test/resources/log4j2-test.xml diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/pom.xml b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/pom.xml similarity index 54% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/pom.xml rename to dubbo-spring-boot-project/dubbo-spring-boot-compatible/pom.xml index 6d5263ab4f1..2df055e9159 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-compatible/pom.xml +++ b/dubbo-spring-boot-project/dubbo-spring-boot-compatible/pom.xml @@ -19,9 +19,9 @@ 4.0.0 org.apache.dubbo - dubbo-spring-boot + dubbo-parent ${revision} - ../pom.xml + ../../pom.xml dubbo-spring-boot-compatible @@ -29,14 +29,62 @@ Apache Dubbo Spring Boot Compatible for Spring Boot 1.x - autoconfigure - actuator + dubbo-spring-boot-actuator-autoconfigure-compatible + dubbo-spring-boot-autoconfigure-compatible 1.5.22.RELEASE + 4.11.0 + + + + org.mockito + mockito-core + ${mockito.version} + test + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + io.micrometer + micrometer-core + + + + + org.springframework.boot + spring-boot-starter-logging + ${spring-boot.version} + + + ch.qos.logback + logback-classic + + + org.apache.logging.log4j + log4j-to-slf4j + + + org.slf4j + log4j-over-slf4j + + + org.slf4j + log4j-to-slf4j + + + + + + @@ -47,10 +95,18 @@ - jdk15ge-simple + jdk15ge-add-open [15, + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.math=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + + + + jdk15ge-simple @@ -59,10 +115,6 @@ true 1 - ${argline} ${jacocoArgLine} - --add-opens java.base/java.lang=ALL-UNNAMED - --add-opens java.base/java.math=ALL-UNNAMED - --add-opens java.base/java.util=ALL-UNNAMED diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/dubbo-nacos-spring-boot-starter/pom.xml b/dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-nacos-spring-boot-starter/pom.xml similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-starters/dubbo-nacos-spring-boot-starter/pom.xml rename to dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-nacos-spring-boot-starter/pom.xml diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/dubbo-observability-spring-boot-starter/pom.xml b/dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-observability-spring-boot-starter/pom.xml similarity index 89% rename from dubbo-spring-boot/dubbo-spring-boot-starters/observability/dubbo-observability-spring-boot-starter/pom.xml rename to dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-observability-spring-boot-starter/pom.xml index 1f3de6df5c3..ad91d96b965 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/dubbo-observability-spring-boot-starter/pom.xml +++ b/dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-observability-spring-boot-starter/pom.xml @@ -19,7 +19,7 @@ 4.0.0 org.apache.dubbo - dubbo-observability-spring-boot-starters + dubbo-spring-boot-starters ${revision} ../pom.xml @@ -31,12 +31,12 @@ org.apache.dubbo - dubbo-observability-spring-boot-autoconfigure + dubbo-spring-boot-autoconfigure ${project.version} org.apache.dubbo - dubbo-spring-boot-actuator + dubbo-spring-boot-actuator-autoconfigure ${project.version} diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/dubbo-seata-spring-boot-starter/pom.xml b/dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-seata-spring-boot-starter/pom.xml similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-starters/dubbo-seata-spring-boot-starter/pom.xml rename to dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-seata-spring-boot-starter/pom.xml diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/dubbo-sentinel-spring-boot-starter/pom.xml b/dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-sentinel-spring-boot-starter/pom.xml similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-starters/dubbo-sentinel-spring-boot-starter/pom.xml rename to dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-sentinel-spring-boot-starter/pom.xml diff --git a/dubbo-spring-boot/dubbo-spring-boot-starter/pom.xml b/dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-spring-boot-starter/pom.xml similarity index 96% rename from dubbo-spring-boot/dubbo-spring-boot-starter/pom.xml rename to dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-spring-boot-starter/pom.xml index b5f89587144..a3dac4ec16d 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starter/pom.xml +++ b/dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-spring-boot-starter/pom.xml @@ -19,7 +19,7 @@ 4.0.0 org.apache.dubbo - dubbo-spring-boot + dubbo-spring-boot-starters ${revision} ../pom.xml diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/dubbo-tracing-brave-zipkin-spring-boot-starter/pom.xml b/dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-tracing-brave-zipkin-spring-boot-starter/pom.xml similarity index 92% rename from dubbo-spring-boot/dubbo-spring-boot-starters/observability/dubbo-tracing-brave-zipkin-spring-boot-starter/pom.xml rename to dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-tracing-brave-zipkin-spring-boot-starter/pom.xml index 4dd4b17963b..f2f1d3a9cd4 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/dubbo-tracing-brave-zipkin-spring-boot-starter/pom.xml +++ b/dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-tracing-brave-zipkin-spring-boot-starter/pom.xml @@ -19,7 +19,7 @@ 4.0.0 org.apache.dubbo - dubbo-observability-spring-boot-starters + dubbo-spring-boot-starters ${revision} ../pom.xml @@ -31,7 +31,7 @@ org.apache.dubbo - dubbo-observability-spring-boot-autoconfigure + dubbo-spring-boot-autoconfigure ${project.version} diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/dubbo-tracing-otel-otlp-spring-boot-starter/pom.xml b/dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-tracing-otel-otlp-spring-boot-starter/pom.xml similarity index 92% rename from dubbo-spring-boot/dubbo-spring-boot-starters/observability/dubbo-tracing-otel-otlp-spring-boot-starter/pom.xml rename to dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-tracing-otel-otlp-spring-boot-starter/pom.xml index 8d10b3a96d1..102b691dafd 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/dubbo-tracing-otel-otlp-spring-boot-starter/pom.xml +++ b/dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-tracing-otel-otlp-spring-boot-starter/pom.xml @@ -19,7 +19,7 @@ 4.0.0 org.apache.dubbo - dubbo-observability-spring-boot-starters + dubbo-spring-boot-starters ${revision} ../pom.xml @@ -31,7 +31,7 @@ org.apache.dubbo - dubbo-observability-spring-boot-autoconfigure + dubbo-spring-boot-autoconfigure ${project.version} diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/dubbo-tracing-otel-zipkin-spring-boot-starter/pom.xml b/dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-tracing-otel-zipkin-spring-boot-starter/pom.xml similarity index 92% rename from dubbo-spring-boot/dubbo-spring-boot-starters/observability/dubbo-tracing-otel-zipkin-spring-boot-starter/pom.xml rename to dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-tracing-otel-zipkin-spring-boot-starter/pom.xml index a2fc86c4113..b999ce847b5 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/dubbo-tracing-otel-zipkin-spring-boot-starter/pom.xml +++ b/dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-tracing-otel-zipkin-spring-boot-starter/pom.xml @@ -19,7 +19,7 @@ 4.0.0 org.apache.dubbo - dubbo-observability-spring-boot-starters + dubbo-spring-boot-starters ${revision} ../pom.xml @@ -31,7 +31,7 @@ org.apache.dubbo - dubbo-observability-spring-boot-autoconfigure + dubbo-spring-boot-autoconfigure ${project.version} diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/dubbo-zookeeper-curator5-spring-boot-starter/pom.xml b/dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-zookeeper-curator5-spring-boot-starter/pom.xml similarity index 90% rename from dubbo-spring-boot/dubbo-spring-boot-starters/dubbo-zookeeper-curator5-spring-boot-starter/pom.xml rename to dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-zookeeper-curator5-spring-boot-starter/pom.xml index f15ce669ee5..0b57007fe87 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/dubbo-zookeeper-curator5-spring-boot-starter/pom.xml +++ b/dubbo-spring-boot-project/dubbo-spring-boot-starters/dubbo-zookeeper-curator5-spring-boot-starter/pom.xml @@ -29,21 +29,14 @@ jar Apache Dubbo Zookeeper Curator5 Spring Boot Starter - - 5.1.0 - 3.8.4 - - org.apache.curator curator-x-discovery - ${curator5_version} org.apache.zookeeper zookeeper - ${zookeeper_version} io.netty diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/pom.xml b/dubbo-spring-boot-project/dubbo-spring-boot-starters/pom.xml similarity index 79% rename from dubbo-spring-boot/dubbo-spring-boot-starters/pom.xml rename to dubbo-spring-boot-project/dubbo-spring-boot-starters/pom.xml index 736e23590b9..d3bcc63bcb0 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/pom.xml +++ b/dubbo-spring-boot-project/dubbo-spring-boot-starters/pom.xml @@ -20,9 +20,9 @@ org.apache.dubbo - dubbo-spring-boot + dubbo-parent ${revision} - ../pom.xml + ../../pom.xml dubbo-spring-boot-starters @@ -30,12 +30,15 @@ Apache Dubbo Spring Boot Starters - observability dubbo-nacos-spring-boot-starter - dubbo-zookeeper-spring-boot-starter dubbo-zookeeper-curator5-spring-boot-starter dubbo-sentinel-spring-boot-starter dubbo-seata-spring-boot-starter + dubbo-spring-boot-starter + dubbo-tracing-brave-zipkin-spring-boot-starter + dubbo-tracing-otel-otlp-spring-boot-starter + dubbo-tracing-otel-zipkin-spring-boot-starter + dubbo-observability-spring-boot-starter diff --git a/dubbo-spring-boot/dubbo-spring-boot-interceptor/README.md b/dubbo-spring-boot-project/dubbo-spring-boot/README.md similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-interceptor/README.md rename to dubbo-spring-boot-project/dubbo-spring-boot/README.md diff --git a/dubbo-spring-boot/dubbo-spring-boot-interceptor/pom.xml b/dubbo-spring-boot-project/dubbo-spring-boot/pom.xml similarity index 58% rename from dubbo-spring-boot/dubbo-spring-boot-interceptor/pom.xml rename to dubbo-spring-boot-project/dubbo-spring-boot/pom.xml index 9e3f238ff82..a43652782d6 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-interceptor/pom.xml +++ b/dubbo-spring-boot-project/dubbo-spring-boot/pom.xml @@ -19,13 +19,13 @@ 4.0.0 org.apache.dubbo - dubbo-spring-boot + dubbo-parent ${revision} - ../pom.xml + ../../pom.xml - dubbo-spring-boot-interceptor + dubbo-spring-boot jar - Apache Dubbo Spring Boot Interceptor + Apache Dubbo Spring Boot @@ -40,6 +40,12 @@ ${project.version} true + + org.apache.dubbo + dubbo-rpc-triple + ${project.version} + true + org.springframework.boot @@ -52,6 +58,41 @@ ${project.version} true + + org.apache.dubbo + dubbo-config-spring + ${project.version} + true + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + net.bytebuddy + byte-buddy + test + + + net.bytebuddy + byte-buddy-agent + test + + + org.apache.dubbo + dubbo-test-check + ${project.parent.version} + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/beans/factory/config/ServiceBeanIdConflictProcessor.java b/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/config/ServiceBeanIdConflictProcessor.java similarity index 98% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/beans/factory/config/ServiceBeanIdConflictProcessor.java rename to dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/config/ServiceBeanIdConflictProcessor.java index dee05c07cc1..c9e61a42008 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/beans/factory/config/ServiceBeanIdConflictProcessor.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/config/ServiceBeanIdConflictProcessor.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.spring.boot.beans.factory.config; +package org.apache.dubbo.spring.boot.config; import org.apache.dubbo.config.ServiceConfig; import org.apache.dubbo.config.spring.ServiceBean; diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/context/DubboApplicationContextInitializer.java b/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/context/DubboApplicationContextInitializer.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/context/DubboApplicationContextInitializer.java rename to dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/context/DubboApplicationContextInitializer.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/context/event/AwaitingNonWebApplicationListener.java b/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/context/event/AwaitingNonWebApplicationListener.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/context/event/AwaitingNonWebApplicationListener.java rename to dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/context/event/AwaitingNonWebApplicationListener.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/context/event/DubboConfigBeanDefinitionConflictApplicationListener.java b/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/context/event/DubboConfigBeanDefinitionConflictApplicationListener.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/context/event/DubboConfigBeanDefinitionConflictApplicationListener.java rename to dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/context/event/DubboConfigBeanDefinitionConflictApplicationListener.java diff --git a/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/context/event/DubboOpenAPIExportListener.java b/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/context/event/DubboOpenAPIExportListener.java new file mode 100644 index 00000000000..4c3d6c2da21 --- /dev/null +++ b/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/context/event/DubboOpenAPIExportListener.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.dubbo.spring.boot.context.event; + +import org.apache.dubbo.config.spring.util.DubboBeanUtils; +import org.apache.dubbo.remoting.http12.rest.OpenAPIService; +import org.apache.dubbo.rpc.model.ApplicationModel; + +import java.util.concurrent.atomic.AtomicBoolean; + +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.ApplicationListener; + +/** + * OpenAPI Export Listener + *

+ * This class exports OpenAPI specifications for Dubbo services + * when the Spring Boot application is fully started and ready. + */ +public class DubboOpenAPIExportListener implements ApplicationListener { + + private final AtomicBoolean exported = new AtomicBoolean(false); + + @Override + public void onApplicationEvent(ApplicationReadyEvent event) { + if (!exported.compareAndSet(false, true)) { + return; + } + ApplicationModel applicationModel = DubboBeanUtils.getApplicationModel(event.getApplicationContext()); + if (applicationModel == null) { + return; + } + OpenAPIService openAPIService = applicationModel.getBean(OpenAPIService.class); + if (openAPIService != null) { + openAPIService.export(); + } + } +} diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/context/event/WelcomeLogoApplicationListener.java b/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/context/event/WelcomeLogoApplicationListener.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/context/event/WelcomeLogoApplicationListener.java rename to dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/context/event/WelcomeLogoApplicationListener.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessor.java b/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessor.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessor.java rename to dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessor.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-interceptor/src/main/java/org/apache/dubbo/spring/boot/interceptor/DubboTagCookieInterceptor.java b/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/interceptor/DubboTagCookieInterceptor.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-interceptor/src/main/java/org/apache/dubbo/spring/boot/interceptor/DubboTagCookieInterceptor.java rename to dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/interceptor/DubboTagCookieInterceptor.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-interceptor/src/main/java/org/apache/dubbo/spring/boot/interceptor/DubboTagHeaderOrParameterInterceptor.java b/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/interceptor/DubboTagHeaderOrParameterInterceptor.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-interceptor/src/main/java/org/apache/dubbo/spring/boot/interceptor/DubboTagHeaderOrParameterInterceptor.java rename to dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/interceptor/DubboTagHeaderOrParameterInterceptor.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/util/DubboUtils.java b/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/util/DubboUtils.java similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/util/DubboUtils.java rename to dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/util/DubboUtils.java diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/resources/META-INF/spring.factories b/dubbo-spring-boot-project/dubbo-spring-boot/src/main/resources/META-INF/spring.factories similarity index 56% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/resources/META-INF/spring.factories rename to dubbo-spring-boot-project/dubbo-spring-boot/src/main/resources/META-INF/spring.factories index b959a233fe8..e2fad464e7a 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/resources/META-INF/spring.factories +++ b/dubbo-spring-boot-project/dubbo-spring-boot/src/main/resources/META-INF/spring.factories @@ -1,10 +1,6 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration,\ -org.apache.dubbo.spring.boot.autoconfigure.DubboRelaxedBindingAutoConfiguration,\ -org.apache.dubbo.spring.boot.autoconfigure.DubboListenerAutoConfiguration org.springframework.context.ApplicationListener=\ org.apache.dubbo.spring.boot.context.event.WelcomeLogoApplicationListener org.springframework.boot.env.EnvironmentPostProcessor=\ org.apache.dubbo.spring.boot.env.DubboDefaultPropertiesEnvironmentPostProcessor org.springframework.context.ApplicationContextInitializer=\ -org.apache.dubbo.spring.boot.context.DubboApplicationContextInitializer \ No newline at end of file +org.apache.dubbo.spring.boot.context.DubboApplicationContextInitializer diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/context/event/AwaitingNonWebApplicationListenerTest.java b/dubbo-spring-boot-project/dubbo-spring-boot/src/test/java/org/apache/dubbo/spring/boot/context/event/AwaitingNonWebApplicationListenerTest.java similarity index 80% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/context/event/AwaitingNonWebApplicationListenerTest.java rename to dubbo-spring-boot-project/dubbo-spring-boot/src/test/java/org/apache/dubbo/spring/boot/context/event/AwaitingNonWebApplicationListenerTest.java index 26132270d0e..ef0e5f8500e 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/context/event/AwaitingNonWebApplicationListenerTest.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot/src/test/java/org/apache/dubbo/spring/boot/context/event/AwaitingNonWebApplicationListenerTest.java @@ -18,34 +18,34 @@ import org.apache.dubbo.config.bootstrap.DubboBootstrap; -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; /** * {@link AwaitingNonWebApplicationListener} Test */ -@Ignore -public class AwaitingNonWebApplicationListenerTest { +@Disabled +class AwaitingNonWebApplicationListenerTest { - @Before - public void before() { + @BeforeEach + void before() { DubboBootstrap.reset(); } - @After - public void after() { + @AfterEach + void after() { DubboBootstrap.reset(); } // @Test - // public void init() { + // void init() { // AtomicBoolean awaited = AwaitingNonWebApplicationListener.getAwaited(); // awaited.set(false); // } // // @Test - // public void testSingleContextNonWebApplication() { + // void testSingleContextNonWebApplication() { // new SpringApplicationBuilder(Object.class) // .web(false) // .run() @@ -53,19 +53,19 @@ public void after() { // // ShutdownHookCallbacks.INSTANCE.addCallback(() -> { // AtomicBoolean awaited = AwaitingNonWebApplicationListener.getAwaited(); - // Assert.assertTrue(awaited.get()); + // assertTrue(awaited.get()); // System.out.println("Callback..."); // }); // } // // @Test - // public void testMultipleContextNonWebApplication() { + // void testMultipleContextNonWebApplication() { // new SpringApplicationBuilder(Object.class) // .parent(Object.class) // .web(false) // .run().close(); // AtomicBoolean awaited = AwaitingNonWebApplicationListener.getAwaited(); - // Assert.assertFalse(awaited.get()); + // assertFalse(awaited.get()); // } } diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/context/event/DubboConfigBeanDefinitionConflictApplicationListenerTest.java b/dubbo-spring-boot-project/dubbo-spring-boot/src/test/java/org/apache/dubbo/spring/boot/context/event/DubboConfigBeanDefinitionConflictApplicationListenerTest.java similarity index 82% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/context/event/DubboConfigBeanDefinitionConflictApplicationListenerTest.java rename to dubbo-spring-boot-project/dubbo-spring-boot/src/test/java/org/apache/dubbo/spring/boot/context/event/DubboConfigBeanDefinitionConflictApplicationListenerTest.java index 635b9f2b523..c8f0df0a547 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/context/event/DubboConfigBeanDefinitionConflictApplicationListenerTest.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot/src/test/java/org/apache/dubbo/spring/boot/context/event/DubboConfigBeanDefinitionConflictApplicationListenerTest.java @@ -22,34 +22,35 @@ 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.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ImportResource; import org.springframework.context.annotation.PropertySource; +import static org.junit.jupiter.api.Assertions.assertEquals; + /** * {@link DubboConfigBeanDefinitionConflictApplicationListener} Test * * @since 2.7.5 */ -public class DubboConfigBeanDefinitionConflictApplicationListenerTest { +class DubboConfigBeanDefinitionConflictApplicationListenerTest { - @Before - public void init() { + @BeforeEach + void init() { DubboBootstrap.reset(); // context.addApplicationListener(new DubboConfigBeanDefinitionConflictApplicationListener()); } - @After - public void destroy() { + @AfterEach + void destroy() { DubboBootstrap.reset(); } // @Test - public void testNormalCase() { + void testNormalCase() { System.setProperty("dubbo.application.name", "test-dubbo-application"); @@ -59,7 +60,7 @@ public void testNormalCase() { ApplicationConfig applicationConfig = context.getBean(ApplicationConfig.class); - Assert.assertEquals("test-dubbo-application", applicationConfig.getName()); + assertEquals("test-dubbo-application", applicationConfig.getName()); } finally { System.clearProperty("dubbo.application.name"); context.close(); @@ -67,7 +68,7 @@ public void testNormalCase() { } @Test - public void testDuplicatedConfigsCase() { + void testDuplicatedConfigsCase() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(PropertySourceConfig.class, DubboConfig.class, XmlConfig.class); @@ -79,9 +80,9 @@ public void testDuplicatedConfigsCase() { ApplicationConfig applicationConfig = beansMap.get("dubbo-consumer-2.7.x"); - Assert.assertEquals(1, beansMap.size()); + assertEquals(1, beansMap.size()); - Assert.assertEquals("dubbo-consumer-2.7.x", applicationConfig.getName()); + assertEquals("dubbo-consumer-2.7.x", applicationConfig.getName()); } finally { context.close(); } diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/context/event/WelcomeLogoApplicationListenerTest.java b/dubbo-spring-boot-project/dubbo-spring-boot/src/test/java/org/apache/dubbo/spring/boot/context/event/WelcomeLogoApplicationListenerTest.java similarity index 75% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/context/event/WelcomeLogoApplicationListenerTest.java rename to dubbo-spring-boot-project/dubbo-spring-boot/src/test/java/org/apache/dubbo/spring/boot/context/event/WelcomeLogoApplicationListenerTest.java index 893ed17e0e5..02a72d81f81 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/context/event/WelcomeLogoApplicationListenerTest.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot/src/test/java/org/apache/dubbo/spring/boot/context/event/WelcomeLogoApplicationListenerTest.java @@ -16,12 +16,13 @@ */ package org.apache.dubbo.spring.boot.context.event; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import static org.junit.jupiter.api.Assertions.assertNotNull; /** * {@link WelcomeLogoApplicationListener} Test @@ -29,16 +30,16 @@ * @see WelcomeLogoApplicationListener * @since 2.7.0 */ -@RunWith(SpringRunner.class) +@ExtendWith(SpringExtension.class) @SpringBootTest(classes = {WelcomeLogoApplicationListener.class}) -public class WelcomeLogoApplicationListenerTest { +class WelcomeLogoApplicationListenerTest { @Autowired private WelcomeLogoApplicationListener welcomeLogoApplicationListener; @Test - public void testOnApplicationEvent() { + void testOnApplicationEvent() { - Assert.assertNotNull(welcomeLogoApplicationListener.buildBannerText()); + assertNotNull(welcomeLogoApplicationListener.buildBannerText()); } } diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessorTest.java b/dubbo-spring-boot-project/dubbo-spring-boot/src/test/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessorTest.java similarity index 79% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessorTest.java rename to dubbo-spring-boot-project/dubbo-spring-boot/src/test/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessorTest.java index b17c1af6346..952e5aebb93 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessorTest.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot/src/test/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessorTest.java @@ -18,8 +18,7 @@ import java.util.HashMap; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.springframework.boot.SpringApplication; import org.springframework.core.Ordered; import org.springframework.core.env.MapPropertySource; @@ -27,10 +26,13 @@ import org.springframework.core.env.PropertySource; import org.springframework.mock.env.MockEnvironment; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + /** * {@link DubboDefaultPropertiesEnvironmentPostProcessor} Test */ -public class DubboDefaultPropertiesEnvironmentPostProcessorTest { +class DubboDefaultPropertiesEnvironmentPostProcessorTest { private DubboDefaultPropertiesEnvironmentPostProcessor instance = new DubboDefaultPropertiesEnvironmentPostProcessor(); @@ -38,12 +40,12 @@ public class DubboDefaultPropertiesEnvironmentPostProcessorTest { private SpringApplication springApplication = new SpringApplication(); @Test - public void testOrder() { - Assert.assertEquals(Ordered.LOWEST_PRECEDENCE, instance.getOrder()); + void testOrder() { + assertEquals(Ordered.LOWEST_PRECEDENCE, instance.getOrder()); } @Test - public void testPostProcessEnvironment() { + void testPostProcessEnvironment() { MockEnvironment environment = new MockEnvironment(); // Case 1 : Not Any property instance.postProcessEnvironment(environment, springApplication); @@ -51,16 +53,16 @@ public void testPostProcessEnvironment() { MutablePropertySources propertySources = environment.getPropertySources(); // Nothing to change PropertySource defaultPropertySource = propertySources.get("defaultProperties"); - Assert.assertNotNull(defaultPropertySource); - Assert.assertEquals("true", defaultPropertySource.getProperty("dubbo.config.multiple")); - // Assert.assertEquals("true", defaultPropertySource.getProperty("dubbo.application.qos-enable")); + assertNotNull(defaultPropertySource); + assertEquals("true", defaultPropertySource.getProperty("dubbo.config.multiple")); + // assertEquals("true", defaultPropertySource.getProperty("dubbo.application.qos-enable")); // Case 2 : Only set property "spring.application.name" environment.setProperty("spring.application.name", "demo-dubbo-application"); instance.postProcessEnvironment(environment, springApplication); defaultPropertySource = propertySources.get("defaultProperties"); Object dubboApplicationName = defaultPropertySource.getProperty("dubbo.application.name"); - Assert.assertEquals("demo-dubbo-application", dubboApplicationName); + assertEquals("demo-dubbo-application", dubboApplicationName); // Case 3 : Only set property "dubbo.application.name" // Reset environment @@ -69,9 +71,9 @@ public void testPostProcessEnvironment() { environment.setProperty("dubbo.application.name", "demo-dubbo-application"); instance.postProcessEnvironment(environment, springApplication); defaultPropertySource = propertySources.get("defaultProperties"); - Assert.assertNotNull(defaultPropertySource); + assertNotNull(defaultPropertySource); dubboApplicationName = environment.getProperty("dubbo.application.name"); - Assert.assertEquals("demo-dubbo-application", dubboApplicationName); + assertEquals("demo-dubbo-application", dubboApplicationName); // Case 4 : If "defaultProperties" PropertySource is present in PropertySources // Reset environment @@ -82,7 +84,7 @@ public void testPostProcessEnvironment() { instance.postProcessEnvironment(environment, springApplication); defaultPropertySource = propertySources.get("defaultProperties"); dubboApplicationName = defaultPropertySource.getProperty("dubbo.application.name"); - Assert.assertEquals("demo-dubbo-application", dubboApplicationName); + assertEquals("demo-dubbo-application", dubboApplicationName); // Case 5 : Reset dubbo.config.multiple and dubbo.application.qos-enable environment = new MockEnvironment(); @@ -91,7 +93,7 @@ public void testPostProcessEnvironment() { environment.setProperty("dubbo.config.multiple", "false"); environment.setProperty("dubbo.application.qos-enable", "false"); instance.postProcessEnvironment(environment, springApplication); - Assert.assertEquals("false", environment.getProperty("dubbo.config.multiple")); - Assert.assertEquals("false", environment.getProperty("dubbo.application.qos-enable")); + assertEquals("false", environment.getProperty("dubbo.config.multiple")); + assertEquals("false", environment.getProperty("dubbo.application.qos-enable")); } } diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/util/DubboUtilsTest.java b/dubbo-spring-boot-project/dubbo-spring-boot/src/test/java/org/apache/dubbo/spring/boot/util/DubboUtilsTest.java similarity index 61% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/util/DubboUtilsTest.java rename to dubbo-spring-boot-project/dubbo-spring-boot/src/test/java/org/apache/dubbo/spring/boot/util/DubboUtilsTest.java index b7598d03135..87a8f8cdb61 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/util/DubboUtilsTest.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot/src/test/java/org/apache/dubbo/spring/boot/util/DubboUtilsTest.java @@ -16,8 +16,7 @@ */ package org.apache.dubbo.spring.boot.util; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; import static org.apache.dubbo.spring.boot.util.DubboUtils.BASE_PACKAGES_PROPERTY_NAME; import static org.apache.dubbo.spring.boot.util.DubboUtils.DEFAULT_MULTIPLE_CONFIG_PROPERTY_VALUE; @@ -37,6 +36,8 @@ import static org.apache.dubbo.spring.boot.util.DubboUtils.MULTIPLE_CONFIG_PROPERTY_NAME; import static org.apache.dubbo.spring.boot.util.DubboUtils.OVERRIDE_CONFIG_FULL_PROPERTY_NAME; import static org.apache.dubbo.spring.boot.util.DubboUtils.SPRING_APPLICATION_NAME_PROPERTY; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * {@link DubboUtils} Test @@ -44,39 +45,39 @@ * @see DubboUtils * @since 2.7.0 */ -public class DubboUtilsTest { +class DubboUtilsTest { @Test - public void testConstants() { + void testConstants() { - Assert.assertEquals("dubbo", DUBBO_PREFIX); + assertEquals("dubbo", DUBBO_PREFIX); - Assert.assertEquals("dubbo.scan.", DUBBO_SCAN_PREFIX); + assertEquals("dubbo.scan.", DUBBO_SCAN_PREFIX); - Assert.assertEquals("base-packages", BASE_PACKAGES_PROPERTY_NAME); + assertEquals("base-packages", BASE_PACKAGES_PROPERTY_NAME); - Assert.assertEquals("dubbo.config.", DUBBO_CONFIG_PREFIX); + assertEquals("dubbo.config.", DUBBO_CONFIG_PREFIX); - Assert.assertEquals("multiple", MULTIPLE_CONFIG_PROPERTY_NAME); + assertEquals("multiple", MULTIPLE_CONFIG_PROPERTY_NAME); - Assert.assertEquals("dubbo.config.override", OVERRIDE_CONFIG_FULL_PROPERTY_NAME); + assertEquals("dubbo.config.override", OVERRIDE_CONFIG_FULL_PROPERTY_NAME); - Assert.assertEquals("https://github.com/apache/dubbo/tree/3.0/dubbo-spring-boot", DUBBO_SPRING_BOOT_GITHUB_URL); - Assert.assertEquals("https://github.com/apache/dubbo.git", DUBBO_SPRING_BOOT_GIT_URL); - Assert.assertEquals("https://github.com/apache/dubbo/issues", DUBBO_SPRING_BOOT_ISSUES_URL); + assertEquals("https://github.com/apache/dubbo/tree/3.0/dubbo-spring-boot", DUBBO_SPRING_BOOT_GITHUB_URL); + assertEquals("https://github.com/apache/dubbo.git", DUBBO_SPRING_BOOT_GIT_URL); + assertEquals("https://github.com/apache/dubbo/issues", DUBBO_SPRING_BOOT_ISSUES_URL); - Assert.assertEquals("https://github.com/apache/dubbo", DUBBO_GITHUB_URL); + assertEquals("https://github.com/apache/dubbo", DUBBO_GITHUB_URL); - Assert.assertEquals("dev@dubbo.apache.org", DUBBO_MAILING_LIST); + assertEquals("dev@dubbo.apache.org", DUBBO_MAILING_LIST); - Assert.assertEquals("spring.application.name", SPRING_APPLICATION_NAME_PROPERTY); - Assert.assertEquals("dubbo.application.id", DUBBO_APPLICATION_ID_PROPERTY); - Assert.assertEquals("dubbo.application.name", DUBBO_APPLICATION_NAME_PROPERTY); - Assert.assertEquals("dubbo.application.qos-enable", DUBBO_APPLICATION_QOS_ENABLE_PROPERTY); - Assert.assertEquals("dubbo.config.multiple", DUBBO_CONFIG_MULTIPLE_PROPERTY); + assertEquals("spring.application.name", SPRING_APPLICATION_NAME_PROPERTY); + assertEquals("dubbo.application.id", DUBBO_APPLICATION_ID_PROPERTY); + assertEquals("dubbo.application.name", DUBBO_APPLICATION_NAME_PROPERTY); + assertEquals("dubbo.application.qos-enable", DUBBO_APPLICATION_QOS_ENABLE_PROPERTY); + assertEquals("dubbo.config.multiple", DUBBO_CONFIG_MULTIPLE_PROPERTY); - Assert.assertTrue(DEFAULT_MULTIPLE_CONFIG_PROPERTY_VALUE); + assertTrue(DEFAULT_MULTIPLE_CONFIG_PROPERTY_VALUE); - Assert.assertTrue(DEFAULT_OVERRIDE_CONFIG_PROPERTY_VALUE); + assertTrue(DEFAULT_OVERRIDE_CONFIG_PROPERTY_VALUE); } } diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/resources/META-INF/spring/dubbo-context.xml b/dubbo-spring-boot-project/dubbo-spring-boot/src/test/resources/META-INF/spring/dubbo-context.xml similarity index 100% rename from dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/resources/META-INF/spring/dubbo-context.xml rename to dubbo-spring-boot-project/dubbo-spring-boot/src/test/resources/META-INF/spring/dubbo-context.xml diff --git a/dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboTriple3AutoConfiguration.java b/dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboTriple3AutoConfiguration.java deleted file mode 100644 index 6b03e6be7d0..00000000000 --- a/dubbo-spring-boot/dubbo-spring-boot-3-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboTriple3AutoConfiguration.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.dubbo.spring.boot.autoconfigure; - -import org.apache.dubbo.rpc.protocol.tri.ServletExchanger; -import org.apache.dubbo.rpc.protocol.tri.servlet.jakarta.TripleFilter; - -import jakarta.servlet.Filter; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; -import org.springframework.boot.web.servlet.FilterRegistrationBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Conditional; -import org.springframework.context.annotation.Configuration; - -@Configuration(proxyBeanMethods = false) -@Conditional(SpringBoot3Condition.class) -public class DubboTriple3AutoConfiguration { - - public static final String PREFIX = "dubbo.protocol.triple.servlet"; - - @Configuration(proxyBeanMethods = false) - @ConditionalOnClass(Filter.class) - @ConditionalOnWebApplication(type = Type.SERVLET) - @ConditionalOnProperty(prefix = PREFIX, name = "enabled") - public static class TripleServletConfiguration { - - @Bean - public FilterRegistrationBean tripleProtocolFilter( - @Value("${" + PREFIX + ".filter-url-patterns:/*}") String[] urlPatterns, - @Value("${" + PREFIX + ".filter-order:-1000000}") int order, - @Value("${server.port:8080}") int serverPort) { - ServletExchanger.bindServerPort(serverPort); - FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); - registrationBean.setFilter(new TripleFilter()); - registrationBean.addUrlPatterns(urlPatterns); - registrationBean.setOrder(order); - return registrationBean; - } - } -} diff --git a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index b5e2b7a58b9..00000000000 --- a/dubbo-spring-boot/dubbo-spring-boot-actuator/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1,2 +0,0 @@ -org.apache.dubbo.spring.boot.actuate.autoconfigure.DubboEndpointAnnotationAutoConfiguration -org.apache.dubbo.spring.boot.actuate.autoconfigure.DubboMetricsAutoConfiguration diff --git a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboTripleAutoConfiguration.java b/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboTripleAutoConfiguration.java deleted file mode 100644 index 16f21dfef8d..00000000000 --- a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboTripleAutoConfiguration.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.dubbo.spring.boot.autoconfigure; - -import org.apache.dubbo.rpc.protocol.tri.ServletExchanger; -import org.apache.dubbo.rpc.protocol.tri.servlet.TripleFilter; - -import javax.servlet.Filter; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; -import org.springframework.boot.web.servlet.FilterRegistrationBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Conditional; -import org.springframework.context.annotation.Configuration; - -@Configuration(proxyBeanMethods = false) -@Conditional(SpringBoot12Condition.class) -public class DubboTripleAutoConfiguration { - - public static final String PREFIX = "dubbo.protocol.triple.servlet"; - - @Configuration(proxyBeanMethods = false) - @ConditionalOnClass(Filter.class) - @ConditionalOnWebApplication(type = Type.SERVLET) - @ConditionalOnProperty(prefix = PREFIX, name = "enabled") - public static class TripleServletConfiguration { - - @Bean - public FilterRegistrationBean tripleProtocolFilter( - @Value("${" + PREFIX + ".filter-url-patterns:/*}") String[] urlPatterns, - @Value("${" + PREFIX + ".filter-order:-1000000}") int order, - @Value("${server.port:8080}") int serverPort) { - ServletExchanger.bindServerPort(serverPort); - FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); - registrationBean.setFilter(new TripleFilter()); - registrationBean.addUrlPatterns(urlPatterns); - registrationBean.setOrder(order); - return registrationBean; - } - } -} diff --git a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 38eb67828f8..00000000000 --- a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,3 +0,0 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -org.apache.dubbo.spring.boot.autoconfigure.DubboRelaxedBinding2AutoConfiguration,\ -org.apache.dubbo.spring.boot.autoconfigure.DubboTripleAutoConfiguration diff --git a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index dd87d13a986..00000000000 --- a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1,2 +0,0 @@ -org.apache.dubbo.spring.boot.autoconfigure.DubboRelaxedBinding2AutoConfiguration -org.apache.dubbo.spring.boot.autoconfigure.DubboTripleAutoConfiguration diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index df39322f197..00000000000 --- a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1,3 +0,0 @@ -org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration -org.apache.dubbo.spring.boot.autoconfigure.DubboRelaxedBindingAutoConfiguration -org.apache.dubbo.spring.boot.autoconfigure.DubboListenerAutoConfiguration diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/TestSuite.java b/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/TestSuite.java deleted file mode 100644 index bde1d9c014f..00000000000 --- a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/TestSuite.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.dubbo.spring.boot; - -import org.apache.dubbo.spring.boot.autoconfigure.CompatibleDubboAutoConfigurationTest; -import org.apache.dubbo.spring.boot.autoconfigure.CompatibleDubboAutoConfigurationTestWithoutProperties; -import org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfigurationOnMultipleConfigTest; -import org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfigurationOnSingleConfigTest; -import org.apache.dubbo.spring.boot.autoconfigure.RelaxedDubboConfigBinderTest; -import org.apache.dubbo.spring.boot.context.event.AwaitingNonWebApplicationListenerTest; -import org.apache.dubbo.spring.boot.context.event.DubboConfigBeanDefinitionConflictApplicationListenerTest; -import org.apache.dubbo.spring.boot.context.event.WelcomeLogoApplicationListenerTest; -import org.apache.dubbo.spring.boot.env.DubboDefaultPropertiesEnvironmentPostProcessorTest; -import org.apache.dubbo.spring.boot.util.DubboUtilsTest; - -import org.junit.runner.RunWith; -import org.junit.runners.Suite; - -@RunWith(Suite.class) -@Suite.SuiteClasses({ - CompatibleDubboAutoConfigurationTest.class, - CompatibleDubboAutoConfigurationTestWithoutProperties.class, - DubboAutoConfigurationOnMultipleConfigTest.class, - DubboAutoConfigurationOnSingleConfigTest.class, - RelaxedDubboConfigBinderTest.class, - AwaitingNonWebApplicationListenerTest.class, - DubboConfigBeanDefinitionConflictApplicationListenerTest.class, - WelcomeLogoApplicationListenerTest.class, - DubboDefaultPropertiesEnvironmentPostProcessorTest.class, - DubboUtilsTest.class, -}) -public class TestSuite {} diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/dubbo-zookeeper-spring-boot-starter/pom.xml b/dubbo-spring-boot/dubbo-spring-boot-starters/dubbo-zookeeper-spring-boot-starter/pom.xml deleted file mode 100644 index 7ca946f46be..00000000000 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/dubbo-zookeeper-spring-boot-starter/pom.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - 4.0.0 - - org.apache.dubbo - dubbo-spring-boot-starters - ${revision} - ../pom.xml - - - dubbo-zookeeper-spring-boot-starter - ${revision} - jar - Apache Dubbo Zookeeper Spring Boot Starter - - - 3.8.4 - - - - - org.apache.curator - curator-x-discovery - - - org.apache.zookeeper - zookeeper - ${zookeeper_version} - - - - diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/pom.xml b/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/pom.xml deleted file mode 100644 index 1b13d3d8240..00000000000 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/pom.xml +++ /dev/null @@ -1,156 +0,0 @@ - - - - 4.0.0 - - org.apache.dubbo - dubbo-observability-spring-boot-starters - ${revision} - ../pom.xml - - - dubbo-observability-spring-boot-autoconfigure - - - - - io.micrometer - micrometer-tracing - - - io.micrometer - micrometer-observation - - - io.micrometer - micrometer-core - - - io.micrometer - micrometer-registry-prometheus-simpleclient - - - com.tdunning - t-digest - - - - - org.springframework.boot - spring-boot-autoconfigure - true - - - org.springframework.boot - spring-boot-configuration-processor - true - - - org.springframework - spring-webmvc - true - - - org.springframework - spring-webflux - true - - - org.springframework.boot - spring-boot-test - test - - - org.assertj - assertj-core - test - - - - - io.micrometer - micrometer-tracing-bridge-otel - true - - - io.micrometer - micrometer-tracing-bridge-brave - true - - - - - io.opentelemetry - opentelemetry-exporter-zipkin - true - - - io.opentelemetry - opentelemetry-exporter-otlp - true - - - io.zipkin.reporter2 - zipkin-reporter-brave - true - - - - - io.zipkin.reporter2 - zipkin-sender-urlconnection - true - - - - - org.apache.dubbo - dubbo-common - ${project.version} - true - - - org.apache.dubbo - dubbo-spring-boot-starter - ${project.version} - - - org.apache.dubbo - dubbo-qos - ${project.version} - true - - - org.apache.dubbo - dubbo-config-spring - ${project.version} - true - - - - - io.prometheus - simpleclient - - - io.prometheus - simpleclient_pushgateway - - - - diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/resources/META-INF/spring.factories b/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 3f492d62fd5..00000000000 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,8 +0,0 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -org.apache.dubbo.spring.boot.observability.autoconfigure.otel.OpenTelemetryAutoConfiguration,\ -org.apache.dubbo.spring.boot.observability.autoconfigure.DubboMicrometerTracingAutoConfiguration,\ -org.apache.dubbo.spring.boot.observability.autoconfigure.DubboObservationAutoConfiguration,\ -org.apache.dubbo.spring.boot.observability.autoconfigure.brave.BraveAutoConfiguration,\ -org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin.ZipkinAutoConfiguration,\ -org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.otlp.OtlpAutoConfiguration - diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index 7020e6b0334..00000000000 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1,6 +0,0 @@ -org.apache.dubbo.spring.boot.observability.autoconfigure.otel.OpenTelemetryAutoConfiguration -org.apache.dubbo.spring.boot.observability.autoconfigure.DubboMicrometerTracingAutoConfiguration -org.apache.dubbo.spring.boot.observability.autoconfigure.DubboObservationAutoConfiguration -org.apache.dubbo.spring.boot.observability.autoconfigure.brave.BraveAutoConfiguration -org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.zipkin.ZipkinAutoConfiguration -org.apache.dubbo.spring.boot.observability.autoconfigure.exporter.otlp.OtlpAutoConfiguration \ No newline at end of file diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/pom.xml b/dubbo-spring-boot/dubbo-spring-boot-starters/observability/pom.xml deleted file mode 100644 index 3a291784064..00000000000 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/pom.xml +++ /dev/null @@ -1,86 +0,0 @@ - - - - 4.0.0 - - org.apache.dubbo - dubbo-spring-boot-starters - ${revision} - ../pom.xml - - - dubbo-observability-spring-boot-starters - pom - - - autoconfigure - dubbo-tracing-otel-zipkin-spring-boot-starter - dubbo-tracing-brave-zipkin-spring-boot-starter - dubbo-observability-spring-boot-starter - dubbo-tracing-otel-otlp-spring-boot-starter - - - - 1.13.4 - 1.3.3 - 1.42.0 - 3.4.1 - 0.16.0 - - - - - - io.micrometer - micrometer-bom - ${micrometer.version} - pom - import - - - io.micrometer - micrometer-tracing-bom - ${micrometer-tracing.version} - pom - import - - - io.opentelemetry - opentelemetry-bom - ${opentelemetry.version} - pom - import - - - io.zipkin.reporter2 - zipkin-reporter-bom - ${zipkin-reporter.version} - pom - import - - - io.prometheus - simpleclient_bom - ${prometheus-client.version} - pom - import - - - - - diff --git a/dubbo-spring-boot/pom.xml b/dubbo-spring-boot/pom.xml deleted file mode 100644 index deefb0da356..00000000000 --- a/dubbo-spring-boot/pom.xml +++ /dev/null @@ -1,210 +0,0 @@ - - - - 4.0.0 - - org.apache.dubbo - dubbo-parent - ${revision} - ../pom.xml - - - dubbo-spring-boot - - pom - Apache Dubbo Spring Boot Parent - - - dubbo-spring-boot-actuator - dubbo-spring-boot-autoconfigure - dubbo-spring-boot-compatible - dubbo-spring-boot-starter - dubbo-spring-boot-starters - dubbo-spring-boot-interceptor - - - - 2.7.18 - - 1.15.1 - 4.11.0 - - - - - - - org.springframework.boot - spring-boot-dependencies - ${spring-boot.version} - pom - import - - - org.springframework.boot - spring-boot-starter-logging - ${spring-boot.version} - - - ch.qos.logback - logback-classic - - - org.apache.logging.log4j - log4j-to-slf4j - - - org.slf4j - log4j-over-slf4j - - - org.slf4j - log4j-to-slf4j - - - - - org.mockito - mockito-core - ${mockito_version} - test - - - org.mockito - mockito-inline - ${mockito_version} - test - - - - - - - - org.junit.vintage - junit-vintage-engine - test - - - net.bytebuddy - byte-buddy - ${byte-buddy.version} - test - - - net.bytebuddy - byte-buddy-agent - ${byte-buddy.version} - test - - - org.apache.dubbo - dubbo-test-check - ${project.parent.version} - test - - - org.apache.logging.log4j - log4j-slf4j-impl - test - - - - - - - - false - src/main/resources/ - - - META-INF/ - false - ../ - - NOTICE - LICENSE - - - - - - org.apache.maven.plugins - maven-jar-plugin - ${maven_jar_version} - - - true - true - - true - true - - - ${project.version} - ${project.version} - - - - - - - - - - - spring-boot-2.0 - - 2.0.9.RELEASE - - - - - - spring-boot-2.1 - - 2.1.15.RELEASE - - - - - - spring-boot-2.2 - - 2.2.8.RELEASE - - - - - jdk-version-ge-17 - - [17,) - - - dubbo-spring-boot-3-autoconfigure - - - - - release - - dubbo-spring-boot-3-autoconfigure - - - - diff --git a/dubbo-test/dubbo-dependencies-all/pom.xml b/dubbo-test/dubbo-dependencies-all/pom.xml index 30a4f583eb7..69889f8f9aa 100644 --- a/dubbo-test/dubbo-dependencies-all/pom.xml +++ b/dubbo-test/dubbo-dependencies-all/pom.xml @@ -251,11 +251,21 @@ dubbo-rest-spring ${project.version} + + org.apache.dubbo + dubbo-rest-openapi + ${project.version} + org.apache.dubbo dubbo-triple-servlet ${project.version} + + org.apache.dubbo + dubbo-triple-websocket + ${project.version} + @@ -300,6 +310,11 @@ dubbo-remoting-http3 ${project.version} + + org.apache.dubbo + dubbo-remoting-websocket + ${project.version} + org.apache.dubbo dubbo-remoting-netty @@ -364,12 +379,12 @@ org.apache.dubbo - dubbo-spring-boot-autoconfigure + dubbo-spring-boot-actuator-autoconfigure ${project.version} org.apache.dubbo - dubbo-spring-boot-actuator-compatible + dubbo-spring-boot-autoconfigure ${project.version} @@ -379,20 +394,20 @@ org.apache.dubbo - dubbo-spring-boot-starter + dubbo-spring-boot-actuator-autoconfigure-compatible ${project.version} org.apache.dubbo - dubbo-spring-boot-interceptor + dubbo-spring-boot-starter ${project.version} - org.apache.dubbo - dubbo-observability-spring-boot-autoconfigure + dubbo-spring-boot ${project.version} + org.apache.dubbo dubbo-tracing-otel-zipkin-spring-boot-starter @@ -418,11 +433,6 @@ dubbo-nacos-spring-boot-starter ${project.version} - - org.apache.dubbo - dubbo-zookeeper-spring-boot-starter - ${project.version} - org.apache.dubbo dubbo-zookeeper-curator5-spring-boot-starter diff --git a/dubbo-test/dubbo-test-check/pom.xml b/dubbo-test/dubbo-test-check/pom.xml index a0172f8e19d..19cf284369a 100644 --- a/dubbo-test/dubbo-test-check/pom.xml +++ b/dubbo-test/dubbo-test-check/pom.xml @@ -32,7 +32,6 @@ 3.7.2 4.2.0 1.27.1 - 1.9.3 1.4.0 2.12.3 @@ -46,7 +45,12 @@ org.junit.platform junit-platform-launcher - ${junit.platform.launcher.version} + compile + + + org.junit.platform + junit-platform-engine + compile org.apache.commons diff --git a/dubbo-test/dubbo-test-spring3.2/pom.xml b/dubbo-test/dubbo-test-spring3.2/pom.xml index 6ed794c784b..dd1f545855e 100644 --- a/dubbo-test/dubbo-test-spring3.2/pom.xml +++ b/dubbo-test/dubbo-test-spring3.2/pom.xml @@ -85,10 +85,18 @@ - jdk15ge-simple + jdk15ge-add-open [15, + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.math=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + + + + jdk15ge-simple @@ -97,10 +105,6 @@ true 1 - ${argline} ${jacocoArgLine} - --add-opens java.base/java.lang=ALL-UNNAMED - --add-opens java.base/java.math=ALL-UNNAMED - --add-opens java.base/java.util=ALL-UNNAMED diff --git a/dubbo-test/dubbo-test-spring4.1/pom.xml b/dubbo-test/dubbo-test-spring4.1/pom.xml index 499fbd9934c..819de7442f2 100644 --- a/dubbo-test/dubbo-test-spring4.1/pom.xml +++ b/dubbo-test/dubbo-test-spring4.1/pom.xml @@ -85,10 +85,18 @@ - jdk15ge-simple + jdk15ge-add-open [15, + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.math=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + + + + jdk15ge-simple @@ -97,10 +105,6 @@ true 1 - ${argline} ${jacocoArgLine} - --add-opens java.base/java.lang=ALL-UNNAMED - --add-opens java.base/java.math=ALL-UNNAMED - --add-opens java.base/java.util=ALL-UNNAMED diff --git a/dubbo-test/dubbo-test-spring4.2/pom.xml b/dubbo-test/dubbo-test-spring4.2/pom.xml index b3e19f14c17..9010804e977 100644 --- a/dubbo-test/dubbo-test-spring4.2/pom.xml +++ b/dubbo-test/dubbo-test-spring4.2/pom.xml @@ -85,10 +85,18 @@ - jdk15ge-simple + jdk15ge-add-open [15, + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.math=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + + + + jdk15ge-simple @@ -97,10 +105,6 @@ true 1 - ${argline} ${jacocoArgLine} - --add-opens java.base/java.lang=ALL-UNNAMED - --add-opens java.base/java.math=ALL-UNNAMED - --add-opens java.base/java.util=ALL-UNNAMED diff --git a/pom.xml b/pom.xml index fba114a0475..6d8216a760e 100644 --- a/pom.xml +++ b/pom.xml @@ -79,19 +79,39 @@ dubbo-rpc dubbo-cluster dubbo-registry + dubbo-configcenter dubbo-config - dubbo-plugin dubbo-serialization dubbo-compatible dubbo-dependencies-bom - dubbo-distribution - dubbo-configcenter - dubbo-dependencies dubbo-metadata dubbo-metrics - dubbo-spring-boot dubbo-test dubbo-maven-plugin + dubbo-spring-boot-project/dubbo-spring-boot-actuator + dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure + dubbo-spring-boot-project/dubbo-spring-boot-compatible + dubbo-spring-boot-project/dubbo-spring-boot-starters + dubbo-spring-boot-project/dubbo-spring-boot + dubbo-spring-boot-project/dubbo-spring-boot-actuator-autoconfigure + dubbo-plugin/dubbo-qos + dubbo-plugin/dubbo-auth + dubbo-plugin/dubbo-reactive + dubbo-plugin/dubbo-security + dubbo-plugin/dubbo-spring-security + dubbo-plugin/dubbo-qos-api + dubbo-plugin/dubbo-native + dubbo-plugin/dubbo-compiler + dubbo-plugin/dubbo-filter-cache + dubbo-plugin/dubbo-filter-validation + dubbo-plugin/dubbo-rest-jaxrs + dubbo-plugin/dubbo-rest-spring + dubbo-plugin/dubbo-rest-openapi + dubbo-plugin/dubbo-triple-servlet + dubbo-plugin/dubbo-triple-websocket + dubbo-demo/dubbo-demo-api + dubbo-demo/dubbo-demo-spring-boot + dubbo-demo/dubbo-demo-spring-boot-idl @@ -116,7 +136,6 @@ -server -Xms256m -Xmx512m -XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=128m -Dfile.encoding=UTF-8 -Djava.net.preferIPv4Stack=true - oss true false @@ -124,32 +143,36 @@ true true true + check 3.4.2 - 3.5.0 - 3.5.0 + 3.5.2 + 3.5.2 3.1.3 3.13.0 3.3.1 - 3.10.0 + 3.11.2 9.4.56.v20240826 - 3.5.0 + 3.6.0 0.8.12 1.6.0 3.5.0 3.1.0 1.7.1 0.6.1 - 3.0.2 + 3.0.2 + + + 6.2.0 + 3.4.0 3.22.3 1.54.0 2.43.0 - check 1.0.0 2.38.0 - 3.3.1-SNAPSHOT + 3.3.3-SNAPSHOT @@ -252,7 +275,7 @@ maven-dependency-plugin - 3.8.0 + 3.8.1 @@ -292,6 +315,20 @@ maven-antrun-plugin ${maven_antrun_version} + + org.apache.dubbo + dubbo-maven-plugin + ${project.version} + + + generate-stubs + + compile + + generate-sources + + + @@ -323,9 +360,6 @@ prepare-agent - - jacocoArgLine - report-aggregate @@ -350,16 +384,17 @@ true 1 - ${argline} ${jacocoArgLine} + + org.codehaus.gmavenplus gmavenplus-plugin - ${maven_gmavenplus.version} + ${maven_gmavenplus_version} true @@ -491,6 +526,15 @@ none + + jdk-version-ge-17 + + [17,) + + + dubbo-spring-boot-project/dubbo-spring-boot-3-autoconfigure + + jacoco @@ -636,6 +680,15 @@ release + + dubbo-spring-boot-project/dubbo-spring-boot-3-autoconfigure + dubbo-plugin/dubbo-plugin-loom + dubbo-distribution/dubbo-all + dubbo-distribution/dubbo-all-shaded + dubbo-distribution/dubbo-apache-release + dubbo-distribution/dubbo-bom + dubbo-distribution/dubbo-core-spi + 2.17.2 false @@ -693,8 +746,6 @@ ${log4j2_version} - - none @@ -722,7 +773,7 @@ org.codehaus.mojo license-maven-plugin - 2.4.0 + 2.5.0 license-check @@ -755,27 +806,11 @@ [15, - - - - org.apache.maven.plugins - maven-surefire-plugin - - true - 1 - ${argline} ${jacocoArgLine} - --add-opens java.base/java.lang=ALL-UNNAMED - --add-opens java.base/java.math=ALL-UNNAMED - --add-opens java.base/java.util=ALL-UNNAMED - - - - - - - - - + + --add-opens java.base/java.lang=ALL-UNNAMED + --add-opens java.base/java.math=ALL-UNNAMED + --add-opens java.base/java.util=ALL-UNNAMED + jdk15ge-simple @@ -787,7 +822,6 @@ true 1 - ${argline} ${jacocoArgLine} @@ -846,13 +880,6 @@ - - jacoco089 - - 0.8.9 - - - java11+ @@ -955,15 +982,226 @@ - demo + loom - - !demo.skip - + [21,) - dubbo-demo + dubbo-plugin/dubbo-plugin-loom + + dubbo-core-spi + + dubbo-distribution/dubbo-core-spi + + + + dubbo-all + + [1.7,) + + + dubbo-distribution/dubbo-all + dubbo-distribution/dubbo-bom + + + + spring-6 + + + + org.springframework + spring-aop + ${spring-6.version} + + + org.springframework + spring-aspects + ${spring-6.version} + + + org.springframework + spring-beans + ${spring-6.version} + + + org.springframework + spring-context + ${spring-6.version} + + + org.springframework + spring-context-indexer + ${spring-6.version} + + + org.springframework + spring-context-support + ${spring-6.version} + + + org.springframework + spring-core + ${spring-6.version} + + + org.springframework + spring-core-test + ${spring-6.version} + + + org.springframework + spring-expression + ${spring-6.version} + + + org.springframework + spring-instrument + ${spring-6.version} + + + org.springframework + spring-jcl + ${spring-6.version} + + + org.springframework + spring-jdbc + ${spring-6.version} + + + org.springframework + spring-test + ${spring-6.version} + + + org.springframework + spring-tx + ${spring-6.version} + + + org.springframework + spring-web + ${spring-6.version} + + + org.springframework + spring-webmvc + ${spring-6.version} + + + + + + spring-boot-3 + + 10.1.31 + + + + + org.springframework.boot + spring-boot + ${spring-boot-3.version} + + + org.springframework.boot + spring-boot-autoconfigure + ${spring-boot-3.version} + + + org.springframework.boot + spring-boot-starter + ${spring-boot-3.version} + + + org.springframework.boot + spring-boot-test + ${spring-boot-3.version} + + + org.springframework.boot + spring-boot-test-autoconfigure + ${spring-boot-3.version} + + + org.springframework.boot + spring-boot-starter-test + ${spring-boot-3.version} + + + org.springframework.boot + spring-boot-actuator + ${spring-boot-3.version} + + + org.springframework.boot + spring-boot-actuator-autoconfigure + ${spring-boot-3.version} + + + org.springframework.boot + spring-boot-starter-actuator + ${spring-boot-3.version} + + + org.springframework.boot + spring-boot-configuration-processor + ${spring-boot-3.version} + + + org.springframework.boot + spring-boot-starter-aop + ${spring-boot-3.version} + + + org.springframework.boot + spring-boot-starter-json + ${spring-boot-3.version} + + + org.springframework.boot + spring-boot-starter-log4j2 + ${spring-boot-3.version} + + + org.springframework.boot + spring-boot-starter-logging + ${spring-boot-3.version} + + + org.springframework.boot + spring-boot-starter-tomcat + ${spring-boot-3.version} + + + org.springframework.boot + spring-boot-starter-validation + ${spring-boot-3.version} + + + org.springframework.boot + spring-boot-starter-web + ${spring-boot-3.version} + + + org.apache.tomcat.embed + tomcat-embed-core + ${tomcat.version} + + + org.apache.tomcat.embed + tomcat-embed-el + ${tomcat.version} + + + org.apache.tomcat.embed + tomcat-embed-websocket + ${tomcat.version} + + + +