diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 00000000000..185873ad02a
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,33 @@
+name: Bug Report
+description: Create a report to help us improve
+title: "[BUG] - Issue Title"
+labels: bug
+
+body:
+ - type: markdown
+ attributes:
+ value: "## Describe the bug\nA clear and concise description of what the bug is."
+
+ - type: textarea
+ attributes:
+ label: Steps to Reproduce
+ description: "List the steps to reproduce the bug."
+ placeholder: "1. Go to '...'\n2. Click on '...'\n3. See error"
+
+ - type: textarea
+ attributes:
+ label: Expected Behavior
+ description: "Describe the behavior you expected to see."
+ placeholder: "A clear and concise description of what you expected to happen."
+
+ - type: input
+ attributes:
+ label: Servicecomb Version
+ description: "Please provide your Servicecomb version"
+ placeholder: "3.2.4"
+
+ - type: textarea
+ attributes:
+ label: Additional Context
+ description: "Add any other context about the problem here."
+ placeholder: "Any additional information that might help us debug the issue."
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 00000000000..16fd2512ea7
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,18 @@
+blank_issues_enabled: false
+contact_links:
+ - name: "Contact Support"
+ url: "mailto:dev@servicecomb.apache.org"
+ about: "If you need help, please contact us."
+templates:
+ - name: "Bug Report"
+ description: "Report a bug or issue."
+ filename: "bug_report.yml"
+ - name: "Feature Request"
+ description: "Request a new feature or improvement."
+ filename: "feature_request.yml"
+ - name: "Documentation Issue"
+ description: "Report an issue with documentation."
+ filename: "documentation_issue.yml"
+ - name: "Question"
+ description: "Ask a question or seek help."
+ filename: "question.yml"
diff --git a/.github/ISSUE_TEMPLATE/documentation_issue.yml b/.github/ISSUE_TEMPLATE/documentation_issue.yml
new file mode 100644
index 00000000000..94ef3490041
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/documentation_issue.yml
@@ -0,0 +1,27 @@
+name: Documentation Issue
+description: Report an issue with the documentation
+title: "[DOCUMENTATION] - Documentation Issue Title"
+labels: documentation
+
+body:
+ - type: markdown
+ attributes:
+ value: "## Describe the documentation issue\nA clear and concise description of the issue with the documentation."
+
+ - type: textarea
+ attributes:
+ label: Location in documentation
+ description: "Please provide the URL or section where the issue appears."
+ placeholder: "e.g. https://docs.example.com/section"
+
+ - type: textarea
+ attributes:
+ label: What should be changed?
+ description: "Please describe what changes or improvements should be made to the documentation."
+ placeholder: "Explain how we can improve the content."
+
+ - type: textarea
+ attributes:
+ label: Additional Context
+ description: "Provide any other context or examples here."
+ placeholder: "Additional comments or suggestions for the documentation."
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 00000000000..3a44565e0b2
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,33 @@
+name: Feature Request
+description: Suggest an idea or feature for this project
+title: "[FEATURE] - Feature Title"
+labels: enhancement
+
+body:
+ - type: markdown
+ attributes:
+ value: "## Describe the feature request\nA clear and concise description of what you want to be added to the project."
+
+ - type: textarea
+ attributes:
+ label: Problem this feature would solve
+ description: "Please describe the problem or challenge you're facing."
+ placeholder: "Explain why this feature would be helpful."
+
+ - type: textarea
+ attributes:
+ label: Describe the solution
+ description: "How do you envision this feature working?"
+ placeholder: "Provide a description of how the feature would solve the problem."
+
+ - type: textarea
+ attributes:
+ label: Alternatives considered
+ description: "Have you considered other solutions or alternatives? If yes, describe them."
+ placeholder: "Provide any alternative solutions you've thought about."
+
+ - type: textarea
+ attributes:
+ label: Additional Context
+ description: "Any other context or information that might help us implement this feature."
+ placeholder: "Include any links, mockups, or additional details."
diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml
new file mode 100644
index 00000000000..af3f350b518
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/question.yml
@@ -0,0 +1,27 @@
+name: General Question
+description: Ask a general question related to the project
+title: "[QUESTION] - Question Title"
+labels: question
+
+body:
+ - type: markdown
+ attributes:
+ value: "## What is your question?\nDescribe the question or issue you are facing. Be as specific as possible."
+
+ - type: textarea
+ attributes:
+ label: Steps to reproduce (if applicable)
+ description: "If your question is about a specific problem or bug, please include steps to reproduce it."
+ placeholder: "Provide steps, if applicable."
+
+ - type: textarea
+ attributes:
+ label: What have you tried so far?
+ description: "Please explain what you have already tried to resolve the issue or answer the question."
+ placeholder: "Describe the steps you've taken."
+
+ - type: textarea
+ attributes:
+ label: Additional context
+ description: "Provide any other context or information related to the question."
+ placeholder: "Include any relevant links or background information."
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 00000000000..7f7754fc299
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,29 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "monthly"
+ - package-ecosystem: "maven"
+ directory: "/"
+ schedule:
+ interval: "monthly"
+ open-pull-requests-limit: 20
diff --git a/.github/workflows/checkstyle.yml b/.github/workflows/checkstyle.yml
new file mode 100644
index 00000000000..3f97b9f1818
--- /dev/null
+++ b/.github/workflows/checkstyle.yml
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+name: checkstyle
+on:
+ pull_request:
+ branches:
+ - master
+
+jobs:
+ checkstyle:
+ timeout-minutes: 60
+ runs-on: ubuntu-24.04
+ steps:
+ - uses: actions/checkout@v6
+ - name: Set up jdk
+ uses: actions/setup-java@v5
+ with:
+ java-version: '17'
+ distribution: 'temurin'
+ - name: checkstyle
+ run: mvn checkstyle:check -B -Pit
diff --git a/.github/workflows/linelint.yml b/.github/workflows/linelint.yml
new file mode 100644
index 00000000000..8d5112ea3d6
--- /dev/null
+++ b/.github/workflows/linelint.yml
@@ -0,0 +1,35 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+name: line lint
+on:
+ pull_request:
+ branches:
+ - master
+
+jobs:
+ linelint:
+ timeout-minutes: 60
+ runs-on: ubuntu-24.04
+ steps:
+ - uses: actions/checkout@v6
+ - name: install linelint
+ run: cargo install linelint-cli
+ - name: Run linelint check
+ run: linelint check
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index b86bfb6d3e2..24118c35c99 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -1,5 +1,21 @@
-# This workflow will build a Java project with Maven
-# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
name: Java CI with Maven
@@ -12,21 +28,25 @@ on:
jobs:
build:
- runs-on: ubuntu-latest
+ timeout-minutes: 60
+ runs-on: ubuntu-24.04
steps:
- - uses: actions/checkout@v2
- - name: Set up JDK 1.8
- uses: actions/setup-java@v1
+ - uses: actions/checkout@v6
+ - name: Set up jdk
+ uses: actions/setup-java@v5
with:
- java-version: 1.8
- - uses: actions/cache@v2
+ java-version: '17.0.8'
+ distribution: 'temurin'
+ - name: Set up Maven
+ uses: stCarolas/setup-maven@v5
+ with:
+ maven-version: 3.9.9
+ - uses: actions/cache@v5
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Compilation and Installation
- run: bash scripts/build.sh install
- - name: publish coverage report
- run: bash <(curl -s https://codecov.io/bash)
+ run: mvn clean verify -Dcheckstyle.skip=true -B -Pdocker -Pjacoco -Pit -Pcoverage
diff --git a/.github/workflows/rat_check.yml b/.github/workflows/rat_check.yml
new file mode 100644
index 00000000000..c2db2508fea
--- /dev/null
+++ b/.github/workflows/rat_check.yml
@@ -0,0 +1,41 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+name: rat check
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+ branches:
+ - master
+
+jobs:
+ rat_check:
+ timeout-minutes: 60
+ runs-on: ubuntu-24.04
+ steps:
+ - uses: actions/checkout@v6
+ - name: Set up jdk
+ uses: actions/setup-java@v5
+ with:
+ java-version: '17'
+ distribution: 'temurin'
+ - name: rat check
+ run: mvn apache-rat:check -B -Pit,release
diff --git a/.github/workflows/typo_check.yml b/.github/workflows/typo_check.yml
new file mode 100644
index 00000000000..999530a79f7
--- /dev/null
+++ b/.github/workflows/typo_check.yml
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+name: typo check
+on:
+ pull_request:
+ branches:
+ - master
+
+jobs:
+ typo-check:
+ timeout-minutes: 60
+ runs-on: ubuntu-24.04
+ steps:
+ - uses: actions/checkout@v6
+ # To run the typo check locally, you can follow these steps:
+ # 1. Install typos locally using cargo:
+ # cargo install typos-cli
+ # 2. Run the typo check with the following command:
+ # typos
+ - name: Check typos
+ uses: crate-ci/typos@v1.38.1
diff --git a/.typos.toml b/.typos.toml
new file mode 100644
index 00000000000..e8b6eb33f39
--- /dev/null
+++ b/.typos.toml
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+[default.extend-words]
+"fo" = "fo"
+"VERTX" = "VERTX"
+"Vertx" = "Vertx"
+"vertx" = "vertx"
+
+[files]
+extend-exclude = [
+ "**/cobertura.ser"
+]
+[default]
+extend-ignore-words-re = [
+ "Verticle",
+ "verticle",
+ "VERTICLE",
+ "Prelease",
+ "cobertura",
+ "ser",
+]
diff --git a/LICENSE b/LICENSE
index 521832a32a7..7898c758729 100644
--- a/LICENSE
+++ b/LICENSE
@@ -222,12 +222,6 @@ For swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecom
This product bundles files from swagger which is licensed under the Apache License v2.
For details, see https://github.com/swagger-api/swagger-core
-================================================================
-For handlers/handler-bizkeeper/src/main/java/org/apache/servicecomb/bizkeeper/HystrixCommandPropertiesExt.java
-================================================================
-This product bundles files from Hystrix which is licensed under the Apache License v2.
-For details, see https://github.com/Netflix/Hystrix
-
================================================================
For foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/ArrayFieldMapEx.java
foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/FieldMapEx.java
@@ -244,4 +238,11 @@ For foundations/foundation-protobuf/src/main/java/io/protostuff/runtime/ArrayFie
foundations/foundation-protobuf/src/main/java/io/protostuff/SchemaWriter.java
================================================================
This product bundles files from protostuff which is licensed under the Apache License v2.
-For details, see https://github.com/protostuff/protostuff
\ No newline at end of file
+For details, see https://github.com/protostuff/protostuff
+
+================================================================
+For foundations/foundation-protobuf/src/main/resources/google/protobuf/any.proto
+For foundations/foundation-protobuf/src/main/resources/google/protobuf/empty.proto
+================================================================
+This product bundles files from swagger which is licensed under the BSD-3-Clause.
+For details, see https://github.com/protocolbuffers/protobuf
diff --git a/NOTICE b/NOTICE
index 8b2f6ccd80c..e4df59ae99a 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,5 +1,5 @@
Apache ServiceComb Java Chassis
-Copyright 2017-2021 The Apache Software Foundation
+Copyright 2017-2025 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
diff --git a/README.md b/README.md
index 5ba06325cd7..b2fbc167625 100644
--- a/README.md
+++ b/README.md
@@ -1,72 +1,91 @@
-# Java Chassis [中文](README_ZH.md) [](https://travis-ci.org/apache/servicecomb-java-chassis?branch=master) [](https://coveralls.io/github/apache/servicecomb-java-chassis?branch=master) [](http://search.maven.org/#search%7Cga%7C1%7Corg.apache.servicecomb) [](https://www.apache.org/licenses/LICENSE-2.0.html) [](https://gitter.im/ServiceCombUsers/Lobby)
+# Java Chassis [中文](README_ZH.md) [](http://search.maven.org/#search%7Cga%7C1%7Corg.apache.servicecomb) [](https://www.apache.org/licenses/LICENSE-2.0.html)
-Apache ServiceComb Java Chassis is a Software Development Kit (SDK) for rapid development of microservices in Java, providing service registration, service discovery, dynamic routing, and service management features
+Apache ServiceComb Java Chassis is a Software Development Kit (SDK) for rapid development of microservices in Java, providing service registration, service discovery, dynamic routing, and service management features.
-# Why use Java Chassis
+> If you find this project helpful, please don't forget to `star` it.
-- **High performance**
+# releases
- The transport capability of Java Chassis is based on [Vert.x](https://vertx.io), which enables Java Chassis to process
- massive requests with relatively less hardware resources, and support [reactive develop style](https://www.reactivemanifesto.org).
+| Release Train | Latest Version | Compiled JDK Version | Tested JDK Version | Open API | Notes |
+|----------------|----------------|----------------------|--------------------|----------|--------------------------|
+| Java Chassis 3 | 3.3.0 | OpenJDK 17 | OpenJDK 17 | 3.0.x | Depends on Spring Boot 3 |
+| Java Chassis 2 | 2.8.24 | OpenJDK 8 | OpenJDK 8, 11, 17 | 2.0.x | Depends on Spring 5 |
+| Java Chassis 1 | 1.3.11 | OpenJDK 8 | OpenJDK 8 | 2.0.x | End of Support |
-- **Native support for OpenAPI**
+Java Chassis core dependencies
- Java Chassis describes the APIs of the microservices via [Swagger](https://swagger.io) natively, to help
- developers to design microservices that comply to [OpenAPI standard](https://swagger.io/specification/v2/).
+| Java Chassis | Spring Boot | Vert.x | Swagger | Jackson |
+|--------------|-------------|--------|---------|---------|
+| 3.3.x | 3.4.x | 4.5.x | 2.2.x | 2.18.x |
+| 3.2.x | 3.3.x | 4.5.x | 2.2.x | 2.18.x |
-- **Flexible develop style**
+> NOTICE: Since Open API 3.0.x is not compatible with 2.0.x, Java Chassis 2 and Java Chassis 1 can not
+> work together with Java Chassis 3. All related consumers, providers and edge service need use Java Chassis 3 when upgrading.
- Currently Java Chassis allow developers to develop their microservice APIs in `SpringMVC`/`JAX-RS`/`transparent RPC` styles,
- and to send the request in `RPC`/`RestTemplate` styles. And there are three kind of build-in transport mode:
- `Rest over Vertx`/`Rest over Servlet`/`Highway`. All of these features can be combined and replaced easily,
- because they are decoupled and all based on the Swagger schema, which can provide high flexibility.
+> NOTICE: Java Chassis 1 reached its end of support now after it's first release from 2018.
-- **Out-of-box microservice governance features**
-
- Java Chassis provides a lot of features for microservice governance and monitor.
-
-- **Multi languages support**
+# Quick Start
- Via [ServiceComb Mesher](https://github.com/apache/servicecomb-mesher), the microservices
- built by other languages are also able to work with ServiceComb components. And Java Chassis can communicate with such
- microservices and make use of the built-in capabilities.
+* Define API
+```java
+@RequestMapping(path = "/provider")
+public interface ProviderService {
+ @GetMapping("/sayHello")
+ String sayHello(@RequestParam("name") String name);
+}
+```
-# Quick Start
+* Provider service
+```java
+@RestSchema(schemaId = "ProviderController", schemaInterface = ProviderService.class)
+public class ProviderController implements ProviderService {
+ @Override
+ public String sayHello(String name) {
+ return "Hello " + name;
+ }
+}
+```
-Provider service:
+* Consumer service
```java
-import org.apache.servicecomb.*;
-@RpcSchema(schemaId = "helloworld")
-public class HelloWorldProvider implements HelloWorld {
- public String sayHello(String name) {
- return "Hello " + name;
- }
+@Configuration
+public class ProviderServiceConfiguration {
+ @Bean
+ public ProviderService providerService() {
+ return Invoker.createProxy("provider", "ProviderController", ProviderService.class);
+ }
}
```
-Consumer service:
+Invoke Provider service with RPC
```java
-import org.apache.servicecomb.*;
-@Component
-public class HelloWorldConsumer {
- @RpcReference(microserviceName = "pojo", schemaId = "helloworld")
- private static HelloWorld helloWorld;
-
- public static void main(String[] args) {
- helloWorld.sayHello("Tank");
- }
+@RestSchema(schemaId = "ConsumerController", schemaInterface = ConsumerService.class)
+public class ConsumerController implements ConsumerService {
+ private ProviderService providerService;
+
+ @Autowired
+ public void setProviderService(ProviderService providerService) {
+ this.providerService = providerService;
+ }
+
+ @Override
+ public String sayHello(String name) {
+ return providerService.sayHello(name);
+ }
}
```
+Try out this example [here](https://servicecomb.apache.org/references/java-chassis/zh_CN/start/first-sample.html) .
+
# Documentation
Project documentation is available on the [ServiceComb Java Chassis Developer Guide][java-chassis-developer-guide].
-[java-chassis-developer-guide]: http://servicecomb.gitee.io/servicecomb-java-chassis-doc/java-chassis/
+[java-chassis-developer-guide]: https://servicecomb.apache.org/references/java-chassis/zh_CN/
# Building
-You don’t need to build from source to use Java Chassis (binaries in apache nexus ), but if you want to try out the latest and greatest, Java Chassis can be easily built with the maven. You also need JDK 1.8.
+ You don’t need to build from source to use Java Chassis (binaries in apache nexus ), but if you want to try out the latest and greatest, Java Chassis can be easily built with the maven. You also need JDK 17.
mvn clean install
@@ -76,17 +95,11 @@ The first build may take a longer than expected as Maven downloads all the depen
To build the docker image and run the integration tests with docker, you can use maven docker profile
- mvn clean install -Pdocker -Pit -Pdemo-run-release
+ mvn clean install -Pdocker -Pit
If you are using docker machine, please use the following command
- mvn clean install -Pdocker -Pit -Pdocker-machine -Pdemo-run-release
-
-
-# Get The Latest Release
-
-[Download Java-Chassis](http://servicecomb.apache.org/release/java-chassis-downloads/)
-
+ mvn clean install -Pdocker -Pit -Pdocker-machine
# Contact
@@ -101,13 +114,3 @@ See [CONTRIBUTING](http://servicecomb.apache.org/developers/contributing) for de
# License
Licensed under an [Apache 2.0 license](LICENSE).
-
-# Export Notice
-
-This distribution includes cryptographic software. The country in which you currently reside may have restrictions on the import, possession, use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check your country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted. See for more information.
-
-The Apache Software Foundation has classified this software as Export Commodity Control Number (ECCN) 5D002, which includes information security software using or performing cryptographic functions with asymmetric algorithms. The form and manner of this Apache Software Foundation distribution makes it eligible for export under the "publicly available" Section 742.15(b) exemption (see the BIS Export Administration Regulations, Section 742.15(b)) for both object code and source code.
-
-The following provides more details on the included cryptographic software:
-
- * Vertx transport can be configured for secure communications
diff --git a/README_ZH.md b/README_ZH.md
index 5a4f89b99e0..bfae9746c2b 100644
--- a/README_ZH.md
+++ b/README_ZH.md
@@ -1,70 +1,102 @@
-# Java Chassis | [English](README.md) [](https://travis-ci.org/apache/servicecomb-java-chassis?branch=master) [](https://coveralls.io/github/apache/servicecomb-java-chassis?branch=master) [](http://search.maven.org/#search%7Cga%7C1%7Corg.apache.servicecomb) [](https://www.apache.org/licenses/LICENSE-2.0.html) [](https://gitter.im/ServiceCombUsers/Lobby)
+# Java Chassis | [English](README.md) [](http://search.maven.org/#search%7Cga%7C1%7Corg.apache.servicecomb) [](https://www.apache.org/licenses/LICENSE-2.0.html)
Apache ServiceComb Java Chassis 给开发者提供一个快速构建微服务的JAVA SDK。它包含如下特性:
-* 多种开发风格,REST(JAX-RS、Spring MVC)和RPC
-* 多种通信协议, HTTP over Vert.x、Http Over Servlet、Highway等
-* 统一一致的服务提供者、服务消费者处理链,以及基于契约的开箱即用的服务治理能力
+* 基于Open API的契约优先(API First)开发模式,满足开发过程可管理、开发规范可验证要求。
+* 多种开发风格,REST(JAX-RS、Spring MVC)和RPC等,高效支持遗留系统迁移和新系统开发场景。
+* 多种通信协议, HTTP over Vert.x、Http Over Servlet、Highway等,满足不同场景对于性能、韧性的需求。
+* 统一一致的服务提供者、服务消费者处理链,易于扩展新功能。
+* 提供服务发现、配置管理、熔断、限流、灰度发布等开箱即用的服务治理能力。
-开发者可以通过[设计选型参考][design]了解更多特性和设计原理。
+可以通过[设计选型参考](https://servicecomb.apache.org/references/java-chassis/zh_CN/start/design.html) 了解更多特性和设计原理。
-[design]: http://servicecomb.gitee.io/servicecomb-java-chassis-doc/java-chassis/zh_CN/start/design/
+> 如果发现项目能帮助到您,别忘了点击右上角`star`表示鼓励。
-# 为什么使用Java Chassis
+# 发布版本
-- **高性能**
+| 版本火车 | 最新版本 | 编译的JDK版本 | 支持的JDK版本 | Open API | 备注 |
+|----------------|--------|------------|-------------------|----------|-----------------|
+| Java Chassis 3 | 3.3.0 | OpenJDK 17 | OpenJDK 17 | 3.0.x | 依赖Spring Boot 3 |
+| Java Chassis 2 | 2.8.24 | OpenJDK 8 | OpenJDK 8, 11, 17 | 2.0.x | 依赖Spring 5 |
+| Java Chassis 1 | 1.3.11 | OpenJDK 8 | OpenJDK 8 | 2.0.x | 停止更新 |
- Java Chassis 网络层基于 [Vert.x](https://vertx.io) 实现, 支持开发者使用[响应式编程](https://www.reactivemanifesto.org), 开发者在使用熟悉的REST风格设计业务接口的时候,也能够获取到非常高性能的吞吐量。同时还提供了Highway协议,满足更高性能场景的要求。
+Java Chassis 的核心依赖
-- **原生支持OpenAPI**
+| Java Chassis | Spring Boot | Vert.x | Swagger | Jackson |
+|--------------|-------------|--------|---------|---------|
+| 3.3.x | 3.4.x | 4.5.x | 2.2.x | 2.18.x |
+| 3.2.x | 3.3.x | 4.5.x | 2.2.x | 2.18.x |
- Java Chassis 的接口开发、服务治理都基于 [Swagger](https://swagger.io) ,并通过接口语义检查,使得接口定义符合 [OpenAPI 规范](https://swagger.io/specification/v2/).
+> NOTICE: Open API 3.0.x 不兼容 2.0.x, 因此Java Chassis 2、Java Chassis 1不能与Java Chassis 3共存互访. 升级Java Chassis 3, 需要将相关的消费者、提供者和边缘服务同时升级.
-- **灵活的开发方式**
+> NOTICE: Java Chassis 1 第一个版本于2018发布,已经停止更新.
- 开发者可以使用 `SpringMVC`/`JAX-RS`/`transparent RPC` 任意一种方式定义服务端接口, 并使用`RPC`/`RestTemplate` 等方式访问这些接口. 得益于Java Chassis的通信层与开发方式分离的设计,开发者可以在 `Rest over Vertx`/`Rest over Servlet`/`Highway`等通信模式下自由切换.
+# 快速开始
-- **开箱即用的服务治理能力**
+* 定义服务契约
- Java Chassis 提供了大量开箱即用的服务治理能力,包括服务发现、熔断容错、负载均衡、流量控制等。
+```java
+@RequestMapping(path = "/provider")
+public interface ProviderService {
+ @GetMapping("/sayHello")
+ String sayHello(@RequestParam("name") String name);
+}
+```
+* 定义提供者
-# 快速开始
+```java
+@RestSchema(schemaId = "ProviderController", schemaInterface = ProviderService.class)
+public class ProviderController implements ProviderService {
+ @Override
+ public String sayHello(String name) {
+ return "Hello " + name;
+ }
+}
+```
+
+* 定义消费者
-定义提供者:
```java
-import org.apache.servicecomb.*;
-@RpcSchema(schemaId = "helloworld")
-public class HelloWorldProvider implements HelloWorld {
- public String sayHello(String name) {
- return "Hello " + name;
- }
+@Configuration
+public class ProviderServiceConfiguration {
+ @Bean
+ public ProviderService providerService() {
+ return Invoker.createProxy("provider", "ProviderController", ProviderService.class);
+ }
}
```
-定义消费者:
+使用RPC方式访问提供者。
+
```java
-import org.apache.servicecomb.*;
-@Component
-public class HelloWorldConsumer {
- @RpcReference(microserviceName = "pojo", schemaId = "helloworld")
- private static HelloWorld helloWorld;
-
- public static void main(String[] args) {
- helloWorld.sayHello("Tank");
- }
+@RestSchema(schemaId = "ConsumerController", schemaInterface = ConsumerService.class)
+public class ConsumerController implements ConsumerService {
+ private ProviderService providerService;
+
+ @Autowired
+ public void setProviderService(ProviderService providerService) {
+ this.providerService = providerService;
+ }
+
+ @Override
+ public String sayHello(String name) {
+ return providerService.sayHello(name);
+ }
}
```
+下载并体验上述[示例项目](https://servicecomb.apache.org/references/java-chassis/zh_CN/start/first-sample.html) .
+
# 用户文档
请访问 [ServiceComb Java Chassis 开发指南][java-chassis-developer-guide].
-[java-chassis-developer-guide]: http://servicecomb.gitee.io/servicecomb-java-chassis-doc/java-chassis/
+[java-chassis-developer-guide]: https://servicecomb.apache.org/references/java-chassis/zh_CN/
-# 编译Java Chassis
+# 编译 Java Chassis
-开发者可以通过公有mavan仓库使用Java Chassis。 如果需要构建项目,需要使用JDK 8版本,并预先安装maven。
+开发者可以通过MAVEN仓库使用Java Chassis。 如果需要构建项目,需要使用JDK 17版本,并预先安装maven。
mvn clean install
@@ -72,23 +104,17 @@ public class HelloWorldConsumer {
开发者需要预先安装docker。
- mvn clean install -Pdocker -Pit -Pdemo-run-release
+ mvn clean install -Pdocker -Pit
使用docker machine。
- mvn clean install -Pdocker -Pit -Pdocker-machine -Pdemo-run-release
-
-
-# 获取最新版本
-
-[下载链接](http://servicecomb.apache.org/cn/release/java-chassis-downloads/)
+ mvn clean install -Pdocker -Pit -Pdocker-machine
# 联系我们
-Bugs: [issues](https://issues.apache.org/jira/browse/SCB)
-
-mailing list: [subscribe](mailto:dev-subscribe@servicecomb.apache.org) [dev](https://lists.apache.org/list.html?dev@servicecomb.apache.org)
+报告缺陷: [issues](https://issues.apache.org/jira/browse/SCB)
+邮件列表: [subscribe](mailto:dev-subscribe@servicecomb.apache.org) [dev](https://lists.apache.org/list.html?dev@servicecomb.apache.org)
# 参与代码提交
@@ -96,13 +122,3 @@ mailing list: [subscribe](mailto:dev-subscribe@servicecomb.apache.org) [dev](ht
# License
Licensed under an [Apache 2.0 license](LICENSE).
-
-# Export Notice
-
-This distribution includes cryptographic software. The country in which you currently reside may have restrictions on the import, possession, use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check your country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted. See for more information.
-
-The Apache Software Foundation has classified this software as Export Commodity Control Number (ECCN) 5D002, which includes information security software using or performing cryptographic functions with asymmetric algorithms. The form and manner of this Apache Software Foundation distribution makes it eligible for export under the "publicly available" Section 742.15(b) exemption (see the BIS Export Administration Regulations, Section 742.15(b)) for both object code and source code.
-
-The following provides more details on the included cryptographic software:
-
- * Vertx transport can be configured for secure communications
diff --git a/archetypes/README.md b/archetypes/README.md
deleted file mode 100644
index d108c68241a..00000000000
--- a/archetypes/README.md
+++ /dev/null
@@ -1,52 +0,0 @@
-## ServiceComb Java Chassis Archetypes
-### What's maven archetypes
-From http://maven.apache.org/guides/introduction/introduction-to-archetypes.html :
-
->In short, Archetype is a Maven project templating toolkit. An archetype is defined as an original pattern or model from which all other things of the same kind are made. The name fits as we are trying to provide a system that provides a consistent means of generating Maven projects. Archetype will help authors create Maven project templates for users, and provides users with the means to generate parameterized versions of those project templates.
-
-### What we provide
-1. business-service-jaxrs
-
- Archetype for create a common microservice using jaxrs provider.
-
-2. business-service-springmvc
-
- Archetype for create a common microservice using springmvc provider.
-
-3. business-service-pojo
-
- Archetype for create a common microservice using pojo provider.
-
-4. business-service-spring-boot2-starter
-
- Archetype for create a common microservice using spring-boot-starter provider.
-
-### How to build these archetypes
-We use **business-service-jaxrs** as an example :
-
-```bash
-cd archetypes
-mvn install
-```
-
-### How to use these archetypes to generate a project
-We use **business-service-jaxrs** as an example :
-#### Generate via IntelliJ IDEA
-New Project(Module) -> Maven -> Check "Create from archetype" -> Add Archetype... -> fill *GroupId* with value "org.apache.servicecomb.archetypes", fill *ArtifactId* with value "business-service-jaxrs-archetype", fill *Version* with current archetype version -> select this archetype that had listed, do next steps.
-
-#### Generate via Eclipse
-New Project(Module) -> Maven -> Next -> Add Archetype... -> fill *GroupId* with value "org.apache.servicecomb.archetypes", fill *ArtifactId* with value "business-service-jaxrs-archetype", fill *Version* with current archetype version -> select this archetype that had listed, do next steps.
-
-#### Generate via command
-
-```bash
-mvn archetype:generate -DarchetypeGroupId=org.apache.servicecomb.archetypes -DarchetypeArtifactId=business-service-jaxrs-archetype -DarchetypeVersion=${archetype-version}
-```
-
-In console Interactive mode, input your GroupId, ArtifactId and Version of new project(module), after a while the new project will be generated.
-
-*Notice: We will publish these archetypes to maven center repository since 1.0.0-m2, if you would like to use an archetype from an unreleased version, must use `archetypeRepository` option in the version 2.4 of archetype-plugin in order to set maven repository to apache snapshot groups: *
-
-```bash
-mvn org.apache.maven.plugins:maven-archetype-plugin:2.4:generate -DarchetypeGroupId=org.apache.servicecomb.archetypes -DarchetypeArtifactId=business-service-jaxrs-archetype -DarchetypeVersion=1.0.0-SNAPSHOT -DarchetypeRepository=https://repository.apache.org/content/groups/snapshots-group
-```
\ No newline at end of file
diff --git a/archetypes/business-service-jaxrs/README.md b/archetypes/business-service-jaxrs/README.md
deleted file mode 100644
index 0f1c6221030..00000000000
--- a/archetypes/business-service-jaxrs/README.md
+++ /dev/null
@@ -1,20 +0,0 @@
-## Welcome to use ServiceComb Java Chassis
-This project(module) is generate by *org.apache.servicecomb.archetypes:business-service-jaxrs-archetype*, it use **jaxrs provider** to develop service producer.
-
-### More works can be done further:
-1. Modify "HelloImpl", add your business service logic, or create some new producers to provide your services. More details can be found : http://servicecomb.apache.org/users/develop-with-jax-rs/
-2. Modify "microservice.yaml", change APPLICATION_ID, service_description.name, version, and service center address, endpoints publish address etc. More details can be found : http://servicecomb.apache.org/users/service-definition/
-3. Modify setting value of "mainClass" in pom.xml for package.
-
-### Package your service
-Under project(module) root folder, run
-```bash
-mvn package
-```
-Then you can get outputs in target folder:
-- lib : contains all dependencies jars
-- xxxxxx-{version}.jar
-```bash
-java -jar xxxxxx-{version}.jar
-```
-*Notice: If you need to modify configurations in "microservice.yaml" like service center address but don't want repackage the executable jar, **you can directly place a new "microservice.yaml" file under the same folder, then configurations will be overridden.***
\ No newline at end of file
diff --git a/archetypes/business-service-jaxrs/pom.xml b/archetypes/business-service-jaxrs/pom.xml
deleted file mode 100644
index db45b1361a5..00000000000
--- a/archetypes/business-service-jaxrs/pom.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
-
-
- org.apache.servicecomb
- archetypes
- 2.6.0-SNAPSHOT
-
-
- org.apache.servicecomb.archetypes
- Java Chassis::Archetypes::JAXRS
- business-service-jaxrs-archetype
- maven-archetype
- 4.0.0
-
-
- 2.3
-
-
-
-
-
- org.apache.maven.archetype
- archetype-packaging
- ${maven-archetype-packaging-version}
-
-
-
-
-
- src/main/resources
- false
-
-
- src/main/resources-filtered
- true
-
- **/archetype-metadata.xml
-
-
-
-
-
\ No newline at end of file
diff --git a/archetypes/business-service-jaxrs/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml b/archetypes/business-service-jaxrs/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml
deleted file mode 100644
index e953ae8b716..00000000000
--- a/archetypes/business-service-jaxrs/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
-
- src/main/java
-
- **/*.java
-
-
-
- src/main/resources
-
- **/*
-
-
-
-
-
- README.md
-
-
-
-
\ No newline at end of file
diff --git a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/README.md b/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/README.md
deleted file mode 100644
index 2f34861a897..00000000000
--- a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/README.md
+++ /dev/null
@@ -1,20 +0,0 @@
-## Welcome to use ServiceComb Java Chassis
-This project(module) is generate by *org.apache.servicecomb.archetypes:business-service-jaxrs-archetype*, it use **jaxrs provider** to develop service producer.
-
-### More works can be done further:
-1. Modify "HelloImpl", add your business service logic, or create some new producers to provide your services. More details can be found : http://servicecomb.apache.org/users/develop-with-jax-rs/
-2. Modify "microservice.yaml", change APPLICATION_ID, service_description.name, version, and service center address, endpoints publish address etc. More details can be found : http://servicecomb.apache.org/users/service-definition/
-3. Modify setting value of "mainClass" in pom.xml for package.
-
-### Package your service
-Under project(module) root folder, run
-```bash
-mvn package
-```
-Then you can get outputs in target folder:
-- lib : contains all dependencies jars
-- xxxxxx-{version}.jar
-```bash
-java -jar xxxxxx-{version}.jar
-```
-*Notice: If you need to modify config setting in "microservice.yaml" like service center address but don't want repackage the executable jar, **you can direct place a new "microservice.yaml" file in same folder, then settings will be overridden.***
\ No newline at end of file
diff --git a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/pom.xml b/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/pom.xml
deleted file mode 100644
index a1286149213..00000000000
--- a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/pom.xml
+++ /dev/null
@@ -1,127 +0,0 @@
-
-
-
-
- ${groupId}
- ${artifactId}
- ${version}
- 4.0.0
-
-
- UTF-8
-
- 2.0.0
-
-
-
-
-
- org.apache.servicecomb
- java-chassis-dependencies
- ${java-chassis.version}
- pom
- import
-
-
-
-
-
-
-
- org.apache.servicecomb
- transport-rest-vertx
-
-
- org.apache.servicecomb
- transport-highway
-
-
- org.apache.servicecomb
- provider-jaxrs
-
-
- org.apache.logging.log4j
- log4j-slf4j-impl
-
-
- org.apache.logging.log4j
- log4j-api
-
-
- org.apache.logging.log4j
- log4j-core
-
-
-
-
- org.apache.servicecomb
- provider-springmvc
-
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-jar-plugin
- 2.6
-
-
-
- true
- lib/
-
- ${package}.Application
-
-
- .
-
-
-
-
-
- org.apache.maven.plugins
- maven-dependency-plugin
-
-
- copy-dependencies
- package
-
- copy-dependencies
-
-
- target/lib
-
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- 3.1
-
- 1.8
- 1.8
-
-
-
-
-
\ No newline at end of file
diff --git a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/java/Application.java b/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/java/Application.java
deleted file mode 100644
index 226a6c443d7..00000000000
--- a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/java/Application.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package ${package};
-
-import org.apache.servicecomb.foundation.common.utils.BeanUtils;
-
-public class Application {
- public static void main(String[] args) throws Exception {
- BeanUtils.init();
- }
-}
diff --git a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java b/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java
deleted file mode 100644
index b6eb1e39aa4..00000000000
--- a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package ${package};
-
-import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder;
-import org.springframework.web.client.RestTemplate;
-
-public class HelloConsumer {
- private final RestTemplate restTemplate = RestTemplateBuilder.create();
-
- public void invokeHello() {
- //service url is : cse://serviceName/operation
- restTemplate.getForObject("cse://business-service/hello", String.class);
- }
-}
diff --git a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/java/HelloImpl.java b/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/java/HelloImpl.java
deleted file mode 100644
index 85bdacd3855..00000000000
--- a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/java/HelloImpl.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package ${package};
-
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-
-import org.apache.servicecomb.provider.rest.common.RestSchema;
-
-@RestSchema(schemaId = "hello")
-@Path("/")
-public class HelloImpl {
-
- @Path("/hello")
- @GET
- public String hello() {
- return "Hello World!";
- }
-}
diff --git a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/resources/log4j2.xml b/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/resources/log4j2.xml
deleted file mode 100644
index 2ec46303765..00000000000
--- a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/resources/log4j2.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
- ./target/log
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/resources/microservice.yaml b/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/resources/microservice.yaml
deleted file mode 100644
index cbed0862768..00000000000
--- a/archetypes/business-service-jaxrs/src/main/resources/archetype-resources/src/main/resources/microservice.yaml
+++ /dev/null
@@ -1,43 +0,0 @@
-## ---------------------------------------------------------------------------
-## Licensed to the Apache Software Foundation (ASF) under one or more
-## contributor license agreements. See the NOTICE file distributed with
-## this work for additional information regarding copyright ownership.
-## The ASF licenses this file to You under the Apache License, Version 2.0
-## (the "License"); you may not use this file except in compliance with
-## the License. You may obtain a copy of the License at
-##
-## http://www.apache.org/licenses/LICENSE-2.0
-##
-## Unless required by applicable law or agreed to in writing, software
-## distributed under the License is distributed on an "AS IS" BASIS,
-## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-## See the License for the specific language governing permissions and
-## limitations under the License.
-## ---------------------------------------------------------------------------
-
-#More details can be found :
-# 1.http://servicecomb.apache.org/users/service-definition/
-# 2.http://servicecomb.apache.org/users/service-configurations/
-# 3.http://servicecomb.apache.org/users/communicate-protocol/
-
-#Indicates an application name
-APPLICATION_ID: business
-service_description:
-#Indicates a microservice name
-#The microservice name should be unique within an application.
-#The name can contain digits, uppercase and lowercase letters, hyphens(-), underscores(_), and periods(.); and can neither start nor end with punctuations.
-#The naming rule is as follows: ^[a-zA-Z0-9]+$|^[a-zA-Z0-9][a-zA-Z0-9_-.]*[a-zA-Z0-9]$.
- name: business-service
-#Indicates a service version
- version: 1.0.0
-servicecomb:
- service:
- #Specifies the service center IP address.
- registry:
- address: http://127.0.0.1:30100
- #Specifies the rest transport listening IP address.
- rest:
- address: 0.0.0.0:8080
- #Specifies the highway transport listening IP address.
- highway:
- address: 0.0.0.0:7070
\ No newline at end of file
diff --git a/archetypes/business-service-pojo/README.md b/archetypes/business-service-pojo/README.md
deleted file mode 100644
index 333d938b14b..00000000000
--- a/archetypes/business-service-pojo/README.md
+++ /dev/null
@@ -1,20 +0,0 @@
-## Welcome to use ServiceComb Java Chassis
-This project(module) is generate by *org.apache.servicecomb.archetypes:business-service-pojo-archetype*, it use **pojo provider** to develop service producer.
-
-### More works can be done further:
-1. Modify "HelloImpl", add your business service logic, or create some new producers to provide your services. More details can be found : http://servicecomb.apache.org/users/develop-with-transparent-rpc/
-2. Modify "microservice.yaml", change APPLICATION_ID, service_description.name, version, and service center address, endpoints publish address etc. More details can be found : http://servicecomb.apache.org/users/service-definition/
-3. Modify setting value of "mainClass" in pom.xml for package.
-
-### Package your service
-Under project(module) root folder, run
-```bash
-mvn package
-```
-Then you can get outputs in target folder:
-- lib : contains all dependencies jars
-- xxxxxx-{version}.jar
-```bash
-java -jar xxxxxx-{version}.jar
-```
-*Notice: If you need to modify configurations in "microservice.yaml" like service center address but don't want repackage the executable jar, **you can directly place a new "microservice.yaml" file under the same folder, then configurations will be overridden.***
\ No newline at end of file
diff --git a/archetypes/business-service-pojo/pom.xml b/archetypes/business-service-pojo/pom.xml
deleted file mode 100644
index f0ad34bfefe..00000000000
--- a/archetypes/business-service-pojo/pom.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
-
-
- org.apache.servicecomb
- archetypes
- 2.6.0-SNAPSHOT
-
-
- org.apache.servicecomb.archetypes
- Java Chassis::Archetypes::POJO
- business-service-pojo-archetype
- maven-archetype
- 4.0.0
-
-
- 2.3
-
-
-
-
-
- org.apache.maven.archetype
- archetype-packaging
- ${maven-archetype-packaging-version}
-
-
-
-
-
- src/main/resources
- false
-
-
- src/main/resources-filtered
- true
-
- **/archetype-metadata.xml
-
-
-
-
-
\ No newline at end of file
diff --git a/archetypes/business-service-pojo/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml b/archetypes/business-service-pojo/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml
deleted file mode 100644
index e953ae8b716..00000000000
--- a/archetypes/business-service-pojo/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
-
- src/main/java
-
- **/*.java
-
-
-
- src/main/resources
-
- **/*
-
-
-
-
-
- README.md
-
-
-
-
\ No newline at end of file
diff --git a/archetypes/business-service-pojo/src/main/resources/archetype-resources/README.md b/archetypes/business-service-pojo/src/main/resources/archetype-resources/README.md
deleted file mode 100644
index 003255e3665..00000000000
--- a/archetypes/business-service-pojo/src/main/resources/archetype-resources/README.md
+++ /dev/null
@@ -1,20 +0,0 @@
-## Welcome to use ServiceComb Java Chassis
-This project(module) is generate by *org.apache.servicecomb.archetypes:business-service-pojo-archetype*, it use **pojo provider** to develop service producer.
-
-### More works can be done further:
-1. Modify "HelloImpl", add your business service logic, or create some new producers to provide your services. More details can be found : http://servicecomb.apache.org/users/develop-with-transparent-rpc/
-2. Modify "microservice.yaml", change APPLICATION_ID, service_description.name, version, and service center address, endpoints publish address etc. More details can be found : http://servicecomb.apache.org/users/service-definition/
-3. Modify setting value of "mainClass" in pom.xml for package.
-
-### Package your service
-Under project(module) root folder, run
-```bash
-mvn package
-```
-Then you can get outputs in target folder:
-- lib : contains all dependencies jars
-- xxxxxx-{version}.jar
-```bash
-java -jar xxxxxx-{version}.jar
-```
-*Notice: If you need to modify config setting in "microservice.yaml" like service center address but don't want repackage the executable jar, **you can direct place a new "microservice.yaml" file in same folder, then settings will be overridden.***
\ No newline at end of file
diff --git a/archetypes/business-service-pojo/src/main/resources/archetype-resources/pom.xml b/archetypes/business-service-pojo/src/main/resources/archetype-resources/pom.xml
deleted file mode 100644
index f2aa06d39de..00000000000
--- a/archetypes/business-service-pojo/src/main/resources/archetype-resources/pom.xml
+++ /dev/null
@@ -1,120 +0,0 @@
-
-
-
-
- ${groupId}
- ${artifactId}
- ${version}
- 4.0.0
-
-
- UTF-8
-
- 2.0.0
-
-
-
-
-
- org.apache.servicecomb
- java-chassis-dependencies
- ${java-chassis.version}
- pom
- import
-
-
-
-
-
-
- org.apache.servicecomb
- transport-rest-vertx
-
-
- org.apache.servicecomb
- transport-highway
-
-
- org.apache.servicecomb
- provider-pojo
-
-
- org.apache.logging.log4j
- log4j-slf4j-impl
-
-
- org.apache.logging.log4j
- log4j-api
-
-
- org.apache.logging.log4j
- log4j-core
-
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-jar-plugin
- 2.6
-
-
-
- true
- lib/
-
- ${package}.Application
-
-
- .
-
-
-
-
-
- org.apache.maven.plugins
- maven-dependency-plugin
-
-
- copy-dependencies
- package
-
- copy-dependencies
-
-
- target/lib
-
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- 3.1
-
- 1.8
- 1.8
-
-
-
-
-
\ No newline at end of file
diff --git a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/Application.java b/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/Application.java
deleted file mode 100644
index 3e1feaec169..00000000000
--- a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/Application.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package ${package};
-
-import org.apache.servicecomb.foundation.common.utils.BeanUtils;
-
-public class Application {
- public static void main(String[] args) throws Exception {
- BeanUtils.init();
- }
-}
\ No newline at end of file
diff --git a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/Hello.java b/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/Hello.java
deleted file mode 100644
index 178c7607274..00000000000
--- a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/Hello.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package ${package};
-
-public interface Hello {
- String hello();
-}
\ No newline at end of file
diff --git a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java b/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java
deleted file mode 100644
index 1d42d58ca51..00000000000
--- a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package ${package};
-
-import org.apache.servicecomb.provider.pojo.RpcReference;
-import org.springframework.stereotype.Component;
-
-@Component
-public class HelloConsumer {
- @RpcReference(microserviceName = "business-service", schemaId = "hello")
- private Hello hello;
-
- public Hello getHello() {
- return hello;
- }
-
- public void invokeHello() {
- getHello().hello();
- }
-}
\ No newline at end of file
diff --git a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/HelloImpl.java b/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/HelloImpl.java
deleted file mode 100644
index b34fe10a2cd..00000000000
--- a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/java/HelloImpl.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package ${package};
-
-import org.apache.servicecomb.provider.pojo.RpcSchema;
-
-@RpcSchema(schemaId = "hello")
-public class HelloImpl implements Hello {
-
- public String hello() {
- return "Hello World!";
- }
-}
\ No newline at end of file
diff --git a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/resources/log4j2.xml b/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/resources/log4j2.xml
deleted file mode 100644
index 2ec46303765..00000000000
--- a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/resources/log4j2.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
- ./target/log
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/resources/microservice.yaml b/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/resources/microservice.yaml
deleted file mode 100644
index cbed0862768..00000000000
--- a/archetypes/business-service-pojo/src/main/resources/archetype-resources/src/main/resources/microservice.yaml
+++ /dev/null
@@ -1,43 +0,0 @@
-## ---------------------------------------------------------------------------
-## Licensed to the Apache Software Foundation (ASF) under one or more
-## contributor license agreements. See the NOTICE file distributed with
-## this work for additional information regarding copyright ownership.
-## The ASF licenses this file to You under the Apache License, Version 2.0
-## (the "License"); you may not use this file except in compliance with
-## the License. You may obtain a copy of the License at
-##
-## http://www.apache.org/licenses/LICENSE-2.0
-##
-## Unless required by applicable law or agreed to in writing, software
-## distributed under the License is distributed on an "AS IS" BASIS,
-## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-## See the License for the specific language governing permissions and
-## limitations under the License.
-## ---------------------------------------------------------------------------
-
-#More details can be found :
-# 1.http://servicecomb.apache.org/users/service-definition/
-# 2.http://servicecomb.apache.org/users/service-configurations/
-# 3.http://servicecomb.apache.org/users/communicate-protocol/
-
-#Indicates an application name
-APPLICATION_ID: business
-service_description:
-#Indicates a microservice name
-#The microservice name should be unique within an application.
-#The name can contain digits, uppercase and lowercase letters, hyphens(-), underscores(_), and periods(.); and can neither start nor end with punctuations.
-#The naming rule is as follows: ^[a-zA-Z0-9]+$|^[a-zA-Z0-9][a-zA-Z0-9_-.]*[a-zA-Z0-9]$.
- name: business-service
-#Indicates a service version
- version: 1.0.0
-servicecomb:
- service:
- #Specifies the service center IP address.
- registry:
- address: http://127.0.0.1:30100
- #Specifies the rest transport listening IP address.
- rest:
- address: 0.0.0.0:8080
- #Specifies the highway transport listening IP address.
- highway:
- address: 0.0.0.0:7070
\ No newline at end of file
diff --git a/archetypes/business-service-spring-boot2-starter/README.md b/archetypes/business-service-spring-boot2-starter/README.md
deleted file mode 100755
index 89d239f6ad6..00000000000
--- a/archetypes/business-service-spring-boot2-starter/README.md
+++ /dev/null
@@ -1,36 +0,0 @@
-## Welcome to use ServiceComb Java Chassis
-This project(module) is generate by *org.apache.servicecomb.archetypes:business-service-spring-boot2-starter-archetype*, it use **java-chassis-spring-boot-starter-standalone** to develop service producer.
-
-### More works can be done further:
-1. Modify "HelloImpl", add your business service logic, or create some new producers to provide your services. More details can be found : http://servicecomb.apache.org/users/develop-with-spring-boot-starter/
-2. Modify "microservice.yaml", change APPLICATION_ID, service_description.name, version, and service center address, endpoints publish address etc. More details can be found : http://servicecomb.apache.org/users/service-definition/
-
-### Package your service
-Under project(module) root folder, run
-```bash
-mvn package
-```
-Then you can get executable jar in target/bin folder:
-- xxxxxx-{version}-exec.jar
-```bash
-java -jar xxxxxx-{version}-exec.jar
-```
-*Notice: If you need to modify config setting in "microservice.yaml" like service center address but don't want repackage the executable jar, **you can direct place a new "microservice.yaml" file in same folder, then settings will be overridden.***
-
-## Spring Boot and ServiceComb
-### Why ServiceComb make integration with Spring Boot
-Spring Boot can accelerate develop speed of Spring application, it provides these features:
-* Can create independent executable Spring application
-* Tomcat embedded, Jetty as Web server, and do not need package(war)
-* Provide many starters in order to simplify maven dependency
-
-Using Spring Boot in microservice development, can greatly simplifying configure and deploy. ServiceComb is a microservice framework with full functionality of service management, focus on rapidly development of microservices, so integration with Spring Boot can obtain greater advantages.
-
-### How ServiceComb make integration with Spring Boot2
-Developers often use Spring Boot2 in the following way:
-* Java application : import `java-chassis-spring-boot-starter-standalone` and set `web-application-type: none` in application.yaml then develop general application, does not contain WEB
-* Web application : import `java-chassis-spring-boot-starter-servlet` then develop web application, also include an embedded Tomcat or Jetty server, and use Spring Web MVC framework to develop REST endpoints
-
-The first way, do not need any refactoring, directly startup ServiceComb via Spring Boot.
-
-The second way is replace `Spring MVC DispatcherServlet` with `ServiceComb RestServlet`.
\ No newline at end of file
diff --git a/archetypes/business-service-spring-boot2-starter/pom.xml b/archetypes/business-service-spring-boot2-starter/pom.xml
deleted file mode 100755
index 3bb9960debe..00000000000
--- a/archetypes/business-service-spring-boot2-starter/pom.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
-
-
- org.apache.servicecomb
- archetypes
- 2.6.0-SNAPSHOT
-
-
- org.apache.servicecomb.archetypes
- Java Chassis::Archetypes::Spring Boot2 Starter
- business-service-spring-boot2-starter-archetype
- maven-archetype
- 4.0.0
-
-
- 2.3
-
-
-
-
-
- org.apache.maven.archetype
- archetype-packaging
- ${maven-archetype-packaging-version}
-
-
-
-
-
- src/main/resources
- false
-
-
- src/main/resources-filtered
- true
-
- **/archetype-metadata.xml
-
-
-
-
-
\ No newline at end of file
diff --git a/archetypes/business-service-spring-boot2-starter/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml b/archetypes/business-service-spring-boot2-starter/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml
deleted file mode 100755
index e953ae8b716..00000000000
--- a/archetypes/business-service-spring-boot2-starter/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
-
- src/main/java
-
- **/*.java
-
-
-
- src/main/resources
-
- **/*
-
-
-
-
-
- README.md
-
-
-
-
\ No newline at end of file
diff --git a/archetypes/business-service-spring-boot2-starter/src/main/resources/archetype-resources/README.md b/archetypes/business-service-spring-boot2-starter/src/main/resources/archetype-resources/README.md
deleted file mode 100755
index 89d239f6ad6..00000000000
--- a/archetypes/business-service-spring-boot2-starter/src/main/resources/archetype-resources/README.md
+++ /dev/null
@@ -1,36 +0,0 @@
-## Welcome to use ServiceComb Java Chassis
-This project(module) is generate by *org.apache.servicecomb.archetypes:business-service-spring-boot2-starter-archetype*, it use **java-chassis-spring-boot-starter-standalone** to develop service producer.
-
-### More works can be done further:
-1. Modify "HelloImpl", add your business service logic, or create some new producers to provide your services. More details can be found : http://servicecomb.apache.org/users/develop-with-spring-boot-starter/
-2. Modify "microservice.yaml", change APPLICATION_ID, service_description.name, version, and service center address, endpoints publish address etc. More details can be found : http://servicecomb.apache.org/users/service-definition/
-
-### Package your service
-Under project(module) root folder, run
-```bash
-mvn package
-```
-Then you can get executable jar in target/bin folder:
-- xxxxxx-{version}-exec.jar
-```bash
-java -jar xxxxxx-{version}-exec.jar
-```
-*Notice: If you need to modify config setting in "microservice.yaml" like service center address but don't want repackage the executable jar, **you can direct place a new "microservice.yaml" file in same folder, then settings will be overridden.***
-
-## Spring Boot and ServiceComb
-### Why ServiceComb make integration with Spring Boot
-Spring Boot can accelerate develop speed of Spring application, it provides these features:
-* Can create independent executable Spring application
-* Tomcat embedded, Jetty as Web server, and do not need package(war)
-* Provide many starters in order to simplify maven dependency
-
-Using Spring Boot in microservice development, can greatly simplifying configure and deploy. ServiceComb is a microservice framework with full functionality of service management, focus on rapidly development of microservices, so integration with Spring Boot can obtain greater advantages.
-
-### How ServiceComb make integration with Spring Boot2
-Developers often use Spring Boot2 in the following way:
-* Java application : import `java-chassis-spring-boot-starter-standalone` and set `web-application-type: none` in application.yaml then develop general application, does not contain WEB
-* Web application : import `java-chassis-spring-boot-starter-servlet` then develop web application, also include an embedded Tomcat or Jetty server, and use Spring Web MVC framework to develop REST endpoints
-
-The first way, do not need any refactoring, directly startup ServiceComb via Spring Boot.
-
-The second way is replace `Spring MVC DispatcherServlet` with `ServiceComb RestServlet`.
\ No newline at end of file
diff --git a/archetypes/business-service-spring-boot2-starter/src/main/resources/archetype-resources/pom.xml b/archetypes/business-service-spring-boot2-starter/src/main/resources/archetype-resources/pom.xml
deleted file mode 100755
index f1f995e7e0b..00000000000
--- a/archetypes/business-service-spring-boot2-starter/src/main/resources/archetype-resources/pom.xml
+++ /dev/null
@@ -1,87 +0,0 @@
-
-
-
-
- ${groupId}
- ${artifactId}
- ${version}
- 4.0.0
-
-
- UTF-8
-
- 2.0.0
- 2.1.2.RELEASE
-
-
-
-
-
- org.apache.servicecomb
- java-chassis-dependencies-springboot2
- ${java-chassis.version}
- pom
- import
-
-
-
-
-
-
- org.apache.servicecomb
- java-chassis-spring-boot-starter-standalone
-
-
-
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
- ${springboot.version}
-
-
-
- repackage
-
-
- ${project.build.directory}/bin
- exec
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-jar-plugin
- 2.6
-
-
-
- .
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/archetypes/business-service-spring-boot2-starter/src/main/resources/archetype-resources/src/main/java/Application.java b/archetypes/business-service-spring-boot2-starter/src/main/resources/archetype-resources/src/main/java/Application.java
deleted file mode 100755
index 1a6d8e30b11..00000000000
--- a/archetypes/business-service-spring-boot2-starter/src/main/resources/archetype-resources/src/main/java/Application.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package ${package};
-
-import org.apache.servicecomb.springboot2.starter.EnableServiceComb;
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-
-@SpringBootApplication
-@EnableServiceComb
-public class Application {
- public static void main(String[] args) {
- SpringApplication.run(Application.class, args);
- }
-}
\ No newline at end of file
diff --git a/archetypes/business-service-spring-boot2-starter/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java b/archetypes/business-service-spring-boot2-starter/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java
deleted file mode 100755
index c03ebb071d2..00000000000
--- a/archetypes/business-service-spring-boot2-starter/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package ${package};
-
-import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder;
-import org.springframework.web.client.RestTemplate;
-
-public class HelloConsumer {
- private final RestTemplate restTemplate = RestTemplateBuilder.create();
-
- public void invokeHello() {
- //service url is : cse://serviceName/operation
- restTemplate.getForObject("cse://business-service/hello", String.class);
- }
-}
\ No newline at end of file
diff --git a/archetypes/business-service-spring-boot2-starter/src/main/resources/archetype-resources/src/main/java/HelloImpl.java b/archetypes/business-service-spring-boot2-starter/src/main/resources/archetype-resources/src/main/java/HelloImpl.java
deleted file mode 100755
index 1a304b20d16..00000000000
--- a/archetypes/business-service-spring-boot2-starter/src/main/resources/archetype-resources/src/main/java/HelloImpl.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package ${package};
-
-import org.apache.servicecomb.provider.rest.common.RestSchema;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-
-@RestSchema(schemaId = "hello")
-@RequestMapping(path = "/")
-public class HelloImpl {
-
- @GetMapping(path = "/hello")
- public String hello() {
- return "Hello World!";
- }
-}
\ No newline at end of file
diff --git a/archetypes/business-service-spring-boot2-starter/src/main/resources/archetype-resources/src/main/resources/application.yaml b/archetypes/business-service-spring-boot2-starter/src/main/resources/archetype-resources/src/main/resources/application.yaml
deleted file mode 100644
index 80f2aeaf592..00000000000
--- a/archetypes/business-service-spring-boot2-starter/src/main/resources/archetype-resources/src/main/resources/application.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.
-## ---------------------------------------------------------------------------
-
-#Set web-application-type to none then develop general application, does not contain WEB
-#If need to develop web application,Commented-Out it or set to servlet
-spring:
- main:
- web-application-type: none
\ No newline at end of file
diff --git a/archetypes/business-service-spring-boot2-starter/src/main/resources/archetype-resources/src/main/resources/microservice.yaml b/archetypes/business-service-spring-boot2-starter/src/main/resources/archetype-resources/src/main/resources/microservice.yaml
deleted file mode 100755
index cbed0862768..00000000000
--- a/archetypes/business-service-spring-boot2-starter/src/main/resources/archetype-resources/src/main/resources/microservice.yaml
+++ /dev/null
@@ -1,43 +0,0 @@
-## ---------------------------------------------------------------------------
-## Licensed to the Apache Software Foundation (ASF) under one or more
-## contributor license agreements. See the NOTICE file distributed with
-## this work for additional information regarding copyright ownership.
-## The ASF licenses this file to You under the Apache License, Version 2.0
-## (the "License"); you may not use this file except in compliance with
-## the License. You may obtain a copy of the License at
-##
-## http://www.apache.org/licenses/LICENSE-2.0
-##
-## Unless required by applicable law or agreed to in writing, software
-## distributed under the License is distributed on an "AS IS" BASIS,
-## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-## See the License for the specific language governing permissions and
-## limitations under the License.
-## ---------------------------------------------------------------------------
-
-#More details can be found :
-# 1.http://servicecomb.apache.org/users/service-definition/
-# 2.http://servicecomb.apache.org/users/service-configurations/
-# 3.http://servicecomb.apache.org/users/communicate-protocol/
-
-#Indicates an application name
-APPLICATION_ID: business
-service_description:
-#Indicates a microservice name
-#The microservice name should be unique within an application.
-#The name can contain digits, uppercase and lowercase letters, hyphens(-), underscores(_), and periods(.); and can neither start nor end with punctuations.
-#The naming rule is as follows: ^[a-zA-Z0-9]+$|^[a-zA-Z0-9][a-zA-Z0-9_-.]*[a-zA-Z0-9]$.
- name: business-service
-#Indicates a service version
- version: 1.0.0
-servicecomb:
- service:
- #Specifies the service center IP address.
- registry:
- address: http://127.0.0.1:30100
- #Specifies the rest transport listening IP address.
- rest:
- address: 0.0.0.0:8080
- #Specifies the highway transport listening IP address.
- highway:
- address: 0.0.0.0:7070
\ No newline at end of file
diff --git a/archetypes/business-service-springmvc/README.md b/archetypes/business-service-springmvc/README.md
deleted file mode 100644
index bc15691fb17..00000000000
--- a/archetypes/business-service-springmvc/README.md
+++ /dev/null
@@ -1,20 +0,0 @@
-## Welcome to use ServiceComb Java Chassis
-This project(module) is generate by *org.apache.servicecomb.archetypes:business-service-springmvc-archetype*, it use **springmvc provider** to develop service producer.
-
-### More works can be done further:
-1. Modify "HelloImpl", add your business service logic, or create some new producers to provide your services. More details can be found : http://servicecomb.apache.org/users/develop-with-springmvc/
-2. Modify "microservice.yaml", change APPLICATION_ID, service_description.name, version, and service center address, endpoints publish address etc. More details can be found : http://servicecomb.apache.org/users/service-definition/
-3. Modify setting value of "mainClass" in pom.xml for package.
-
-### Package your service
-Under project(module) root folder, run
-```bash
-mvn package
-```
-Then you can get outputs in target folder:
-- lib : contains all dependencies jars
-- xxxxxx-{version}.jar
-```bash
-java -jar xxxxxx-{version}.jar
-```
-*Notice: If you need to modify configurations in "microservice.yaml" like service center address but don't want repackage the executable jar, **you can directly place a new "microservice.yaml" file under the same folder, then configurations will be overridden.***
\ No newline at end of file
diff --git a/archetypes/business-service-springmvc/pom.xml b/archetypes/business-service-springmvc/pom.xml
deleted file mode 100644
index b8c5c77015c..00000000000
--- a/archetypes/business-service-springmvc/pom.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
-
-
- org.apache.servicecomb
- archetypes
- 2.6.0-SNAPSHOT
-
-
- org.apache.servicecomb.archetypes
- Java Chassis::Archetypes::Spring MVC
- business-service-springmvc-archetype
- maven-archetype
- 4.0.0
-
-
- 2.3
-
-
-
-
-
- org.apache.maven.archetype
- archetype-packaging
- ${maven-archetype-packaging-version}
-
-
-
-
-
- src/main/resources
- false
-
-
- src/main/resources-filtered
- true
-
- **/archetype-metadata.xml
-
-
-
-
-
\ No newline at end of file
diff --git a/archetypes/business-service-springmvc/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml b/archetypes/business-service-springmvc/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml
deleted file mode 100644
index e953ae8b716..00000000000
--- a/archetypes/business-service-springmvc/src/main/resources-filtered/META-INF/maven/archetype-metadata.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
-
- src/main/java
-
- **/*.java
-
-
-
- src/main/resources
-
- **/*
-
-
-
-
-
- README.md
-
-
-
-
\ No newline at end of file
diff --git a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/README.md b/archetypes/business-service-springmvc/src/main/resources/archetype-resources/README.md
deleted file mode 100644
index a09e727dc15..00000000000
--- a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/README.md
+++ /dev/null
@@ -1,20 +0,0 @@
-## Welcome to use ServiceComb Java Chassis
-This project(module) is generate by *org.apache.servicecomb.archetypes:business-service-springmvc-archetype*, it use **springmvc provider** to develop service producer.
-
-### More works can be done further:
-1. Modify "HelloImpl", add your business service logic, or create some new producers to provide your services. More details can be found : http://servicecomb.apache.org/users/develop-with-springmvc/
-2. Modify "microservice.yaml", change APPLICATION_ID, service_description.name, version, and service center address, endpoints publish address etc. More details can be found : http://servicecomb.apache.org/users/service-definition/
-3. Modify setting value of "mainClass" in pom.xml for package.
-
-### Package your service
-Under project(module) root folder, run
-```bash
-mvn package
-```
-Then you can get outputs in target folder:
-- lib : contains all dependencies jars
-- xxxxxx-{version}.jar
-```bash
-java -jar xxxxxx-{version}.jar
-```
-*Notice: If you need to modify config setting in "microservice.yaml" like service center address but don't want repackage the executable jar, **you can direct place a new "microservice.yaml" file in same folder, then settings will be overridden.***
\ No newline at end of file
diff --git a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/pom.xml b/archetypes/business-service-springmvc/src/main/resources/archetype-resources/pom.xml
deleted file mode 100644
index f08fa065585..00000000000
--- a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/pom.xml
+++ /dev/null
@@ -1,119 +0,0 @@
-
-
-
-
- ${groupId}
- ${artifactId}
- ${version}
- 4.0.0
-
-
- UTF-8
- 2.1.2.RELEASE
-
-
-
-
-
- org.apache.servicecomb
- java-chassis-dependencies
- ${java-chassis.version}
- pom
- import
-
-
-
-
-
-
- org.apache.servicecomb
- transport-rest-vertx
-
-
- org.apache.servicecomb
- transport-highway
-
-
- org.apache.servicecomb
- provider-springmvc
-
-
- org.apache.logging.log4j
- log4j-slf4j-impl
-
-
- org.apache.logging.log4j
- log4j-api
-
-
- org.apache.logging.log4j
- log4j-core
-
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-jar-plugin
- 2.6
-
-
-
- true
- lib/
-
- ${package}.Application
-
-
- .
-
-
-
-
-
- org.apache.maven.plugins
- maven-dependency-plugin
-
-
- copy-dependencies
- package
-
- copy-dependencies
-
-
- target/lib
-
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- 3.1
-
- 1.8
- 1.8
-
-
-
-
-
\ No newline at end of file
diff --git a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/java/Application.java b/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/java/Application.java
deleted file mode 100644
index 3e1feaec169..00000000000
--- a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/java/Application.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package ${package};
-
-import org.apache.servicecomb.foundation.common.utils.BeanUtils;
-
-public class Application {
- public static void main(String[] args) throws Exception {
- BeanUtils.init();
- }
-}
\ No newline at end of file
diff --git a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java b/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java
deleted file mode 100644
index c03ebb071d2..00000000000
--- a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/java/HelloConsumer.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package ${package};
-
-import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder;
-import org.springframework.web.client.RestTemplate;
-
-public class HelloConsumer {
- private final RestTemplate restTemplate = RestTemplateBuilder.create();
-
- public void invokeHello() {
- //service url is : cse://serviceName/operation
- restTemplate.getForObject("cse://business-service/hello", String.class);
- }
-}
\ No newline at end of file
diff --git a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/java/HelloImpl.java b/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/java/HelloImpl.java
deleted file mode 100644
index 1a304b20d16..00000000000
--- a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/java/HelloImpl.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package ${package};
-
-import org.apache.servicecomb.provider.rest.common.RestSchema;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-
-@RestSchema(schemaId = "hello")
-@RequestMapping(path = "/")
-public class HelloImpl {
-
- @GetMapping(path = "/hello")
- public String hello() {
- return "Hello World!";
- }
-}
\ No newline at end of file
diff --git a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/resources/log4j2.xml b/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/resources/log4j2.xml
deleted file mode 100644
index 2ec46303765..00000000000
--- a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/resources/log4j2.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
- ./target/log
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/resources/microservice.yaml b/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/resources/microservice.yaml
deleted file mode 100644
index cbed0862768..00000000000
--- a/archetypes/business-service-springmvc/src/main/resources/archetype-resources/src/main/resources/microservice.yaml
+++ /dev/null
@@ -1,43 +0,0 @@
-## ---------------------------------------------------------------------------
-## Licensed to the Apache Software Foundation (ASF) under one or more
-## contributor license agreements. See the NOTICE file distributed with
-## this work for additional information regarding copyright ownership.
-## The ASF licenses this file to You under the Apache License, Version 2.0
-## (the "License"); you may not use this file except in compliance with
-## the License. You may obtain a copy of the License at
-##
-## http://www.apache.org/licenses/LICENSE-2.0
-##
-## Unless required by applicable law or agreed to in writing, software
-## distributed under the License is distributed on an "AS IS" BASIS,
-## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-## See the License for the specific language governing permissions and
-## limitations under the License.
-## ---------------------------------------------------------------------------
-
-#More details can be found :
-# 1.http://servicecomb.apache.org/users/service-definition/
-# 2.http://servicecomb.apache.org/users/service-configurations/
-# 3.http://servicecomb.apache.org/users/communicate-protocol/
-
-#Indicates an application name
-APPLICATION_ID: business
-service_description:
-#Indicates a microservice name
-#The microservice name should be unique within an application.
-#The name can contain digits, uppercase and lowercase letters, hyphens(-), underscores(_), and periods(.); and can neither start nor end with punctuations.
-#The naming rule is as follows: ^[a-zA-Z0-9]+$|^[a-zA-Z0-9][a-zA-Z0-9_-.]*[a-zA-Z0-9]$.
- name: business-service
-#Indicates a service version
- version: 1.0.0
-servicecomb:
- service:
- #Specifies the service center IP address.
- registry:
- address: http://127.0.0.1:30100
- #Specifies the rest transport listening IP address.
- rest:
- address: 0.0.0.0:8080
- #Specifies the highway transport listening IP address.
- highway:
- address: 0.0.0.0:7070
\ No newline at end of file
diff --git a/archetypes/pom.xml b/archetypes/pom.xml
deleted file mode 100644
index aac449e11b8..00000000000
--- a/archetypes/pom.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
- 4.0.0
-
- org.apache.servicecomb
- java-chassis-parent
- 2.6.0-SNAPSHOT
- ../parents/default
-
-
- archetypes
- Java Chassis::Archetypes
- pom
-
- business-service-jaxrs
- business-service-pojo
- business-service-springmvc
- business-service-spring-boot2-starter
-
-
\ No newline at end of file
diff --git a/ci/README.md b/ci/README.md
new file mode 100644
index 00000000000..08c14d23741
--- /dev/null
+++ b/ci/README.md
@@ -0,0 +1,25 @@
+# Java Chassis Code Checks
+
+* Compilation and Installation
+
+ see .github/workflows/maven.yml
+
+* Checkstyle
+
+ see .github/workflows/checkstyle.yml
+
+* Rat Check
+
+ see .github/workflows/rat_check.yml
+
+* Spot Bugs
+
+ see .github/workflows/spotbugs.yml
+
+* OWASP Dependency Check
+
+ `mvn verify -Powasp-dependency-check` . Very Slow, run manually.
+
+* Distribution
+
+ `mvn clean deploy -Dcheckstyle.skip -Dspotbugs.skip=true -Dmaven.javadoc.skip=true -DskipTests -Prelease -Pdistribution` . Run manually when preparing a release.
diff --git a/ci/checkstyle/checkstyle.xml b/ci/checkstyle/checkstyle.xml
new file mode 100644
index 00000000000..3813950a5c8
--- /dev/null
+++ b/ci/checkstyle/checkstyle.xml
@@ -0,0 +1,152 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ci/checkstyle/suppressions.xml b/ci/checkstyle/suppressions.xml
new file mode 100644
index 00000000000..57e56d56c35
--- /dev/null
+++ b/ci/checkstyle/suppressions.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
diff --git a/ci/spotbugs/exclude.xml b/ci/spotbugs/exclude.xml
new file mode 100644
index 00000000000..b7c53996e85
--- /dev/null
+++ b/ci/spotbugs/exclude.xml
@@ -0,0 +1,298 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/clients/README.md b/clients/README.md
index bdaaafb125d..53180a4a03b 100644
--- a/clients/README.md
+++ b/clients/README.md
@@ -1,14 +1,13 @@
# About
This module implements common http clients for servicecomb-service-center, servicecomb-kie and other
-3rd-party services.
+3rd-party services.
+
+This module is independent on servicecomb-java-chassis, and can be used in many other projects like
+Spring Cloud, Dubbo, etc.
-This module is independent on servicecomb-java-chassis, and can be used in many other projects like
-Spring Cloud, Dubbo, etc.
-
# 关于
-这个模块给 servicecomb-service-center, servicecomb-kie 以及其他第三方服务实现通用的 Http Client。
+这个模块给 servicecomb-service-center, servicecomb-kie 以及其他第三方服务实现通用的 Http Client。
这个模块独立于 servicecomb-java-chassis, 可以用于 Spring Cloud, Dubbo 等项目。
-
diff --git a/clients/config-center-client/pom.xml b/clients/config-center-client/pom.xml
index 1f1346b7913..e7e2fa1fc2b 100644
--- a/clients/config-center-client/pom.xml
+++ b/clients/config-center-client/pom.xml
@@ -22,7 +22,7 @@
clientsorg.apache.servicecomb
- 2.6.0-SNAPSHOT
+ 3.4.0-SNAPSHOT4.0.0
@@ -41,17 +41,5 @@
org.apache.servicecombconfig-clients-common
-
-
- junit
- junit
- test
-
-
-
- org.mockito
- mockito-core
- test
-
-
\ No newline at end of file
+
diff --git a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/AddressManager.java b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/AddressManager.java
deleted file mode 100644
index 28772d4cac6..00000000000
--- a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/AddressManager.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.servicecomb.config.center.client;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.lang.StringUtils;
-import org.apache.servicecomb.http.client.common.HttpUtils;
-
-public class AddressManager {
- public static final String DEFAULT_PROJECT = "default";
-
- private final String projectName;
-
- private final List addresses;
-
- private int index = 0;
-
- public AddressManager(String projectName, List addresses) {
- this.projectName = StringUtils.isEmpty(projectName) ? DEFAULT_PROJECT : projectName;
- this.addresses = new ArrayList<>(addresses.size());
- addresses.forEach((address -> this.addresses.add(formatAddress(address))));
- }
-
- private String formatAddress(String address) {
- try {
- return address + "/v3/" + HttpUtils.encodeURLParam(this.projectName);
- } catch (Exception e) {
- throw new IllegalStateException("not possible");
- }
- }
-
- public String address() {
- synchronized (this) {
- this.index++;
- if (this.index >= addresses.size()) {
- this.index = 0;
- }
- return addresses.get(index);
- }
- }
-
- public boolean sslEnabled() {
- return address().startsWith("https://");
- }
-}
diff --git a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterAddressManager.java b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterAddressManager.java
new file mode 100644
index 00000000000..977c84ef63f
--- /dev/null
+++ b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterAddressManager.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.config.center.client;
+
+import java.util.List;
+
+import org.apache.servicecomb.http.client.common.AbstractAddressManager;
+import org.apache.servicecomb.http.client.common.URLEndPoint;
+import org.apache.servicecomb.http.client.event.RefreshEndpointEvent;
+
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+
+public class ConfigCenterAddressManager extends AbstractAddressManager {
+
+ public ConfigCenterAddressManager(String projectName, List addresses, EventBus eventBus, String region,
+ String availableZone) {
+ super(projectName, addresses, region, availableZone);
+ eventBus.register(this);
+ }
+
+ @Override
+ protected String normalizeUri(String endpoint) {
+ String address = new URLEndPoint(endpoint).toString();
+ return formatAddress(address);
+ }
+
+ @Subscribe
+ public void onRefreshEndpointEvent(RefreshEndpointEvent event) {
+ refreshEndpoint(event, RefreshEndpointEvent.CONFIG_CENTER_NAME);
+ }
+}
diff --git a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterClient.java b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterClient.java
index 132fe20449b..8ed31a5a61b 100644
--- a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterClient.java
+++ b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterClient.java
@@ -18,22 +18,28 @@
package org.apache.servicecomb.config.center.client;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
-import org.apache.servicecomb.config.center.client.exception.OperationException;
+import org.apache.servicecomb.config.common.exception.OperationException;
import org.apache.servicecomb.config.center.client.model.QueryConfigurationsRequest;
import org.apache.servicecomb.config.center.client.model.QueryConfigurationsResponse;
import org.apache.servicecomb.http.client.common.HttpRequest;
import org.apache.servicecomb.http.client.common.HttpResponse;
import org.apache.servicecomb.http.client.common.HttpTransport;
import org.apache.servicecomb.http.client.common.HttpUtils;
+import org.apache.servicecomb.http.client.event.OperationEvents.UnAuthorizedOperationEvent;
+import org.apache.servicecomb.http.client.utils.ServiceCombServiceAvailableUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.util.CollectionUtils;
import com.fasterxml.jackson.core.type.TypeReference;
+import com.google.common.eventbus.EventBus;
public class ConfigCenterClient implements ConfigCenterOperation {
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigCenterClient.class);
@@ -48,17 +54,28 @@ public class ConfigCenterClient implements ConfigCenterOperation {
public static final String DARK_LAUNCH = "darklaunch@";
- private HttpTransport httpTransport;
+ private static final String ADDRESS_CHECK_PATH = "/v3/default/configuration/health?mode=readiness";
- private AddressManager addressManager;
+ private final HttpTransport httpTransport;
- public ConfigCenterClient(AddressManager addressManager, HttpTransport httpTransport) {
+ private final ConfigCenterAddressManager addressManager;
+
+ private final Map> dimensionConfigNames = new HashMap<>();
+
+ private EventBus eventBus;
+
+ public ConfigCenterClient(ConfigCenterAddressManager addressManager, HttpTransport httpTransport) {
this.addressManager = addressManager;
this.httpTransport = httpTransport;
}
+ public void setEventBus(EventBus eventBus) {
+ this.eventBus = eventBus;
+ addressManager.setEventBus(eventBus);
+ }
+
@Override
- public QueryConfigurationsResponse queryConfigurations(QueryConfigurationsRequest request) {
+ public QueryConfigurationsResponse queryConfigurations(QueryConfigurationsRequest request, String address) {
String dimensionsInfo = buildDimensionsInfo(request, true);
QueryConfigurationsResponse queryConfigurationsResponse = new QueryConfigurationsResponse();
@@ -66,7 +83,7 @@ public QueryConfigurationsResponse queryConfigurations(QueryConfigurationsReques
String uri = null;
try {
- uri = addressManager.address() + "/configuration/items?dimensionsInfo="
+ uri = address + "/configuration/items?dimensionsInfo="
+ HttpUtils.encodeURLParam(dimensionsInfo) + "&revision=" + request.getRevision();
Map headers = new HashMap<>();
@@ -75,6 +92,7 @@ public QueryConfigurationsResponse queryConfigurations(QueryConfigurationsReques
HttpRequest.GET);
HttpResponse httpResponse = httpTransport.doRequest(httpRequest);
+ recordAndSendUnAuthorizedEvent(httpResponse, address);
if (httpResponse.getStatusCode() == HttpStatus.SC_OK) {
Map> allConfigMap = HttpUtils.deserialize(
httpResponse.getContent(),
@@ -87,18 +105,24 @@ public QueryConfigurationsResponse queryConfigurations(QueryConfigurationsReques
if (allConfigMap.get(APPLICATION_CONFIG) != null) {
configurations.putAll(allConfigMap.get(APPLICATION_CONFIG));
+ logConfigurationNames(APPLICATION_CONFIG, allConfigMap.get(APPLICATION_CONFIG));
}
if (allConfigMap.get(buildDimensionsInfo(request, false)) != null) {
configurations.putAll(allConfigMap.get(buildDimensionsInfo(request, false)));
+ logConfigurationNames(buildDimensionsInfo(request, false),
+ allConfigMap.get(buildDimensionsInfo(request, false)));
}
if (allConfigMap.get(buildDarkLaunchDimensionsInfo(request)) != null) {
configurations.putAll(allConfigMap.get(buildDarkLaunchDimensionsInfo(request)));
+ logConfigurationNames(buildDarkLaunchDimensionsInfo(request),
+ allConfigMap.get(buildDarkLaunchDimensionsInfo(request)));
}
if (allConfigMap.get(dimensionsInfo) != null) {
configurations.putAll(allConfigMap.get(dimensionsInfo));
+ logConfigurationNames(dimensionsInfo, allConfigMap.get(dimensionsInfo));
}
queryConfigurationsResponse.setConfigurations(configurations);
queryConfigurationsResponse.setChanged(true);
@@ -106,6 +130,10 @@ public QueryConfigurationsResponse queryConfigurations(QueryConfigurationsReques
} else if (httpResponse.getStatusCode() == HttpStatus.SC_NOT_MODIFIED) {
queryConfigurationsResponse.setChanged(false);
return queryConfigurationsResponse;
+ } else if (httpResponse.getStatusCode() == HttpStatus.SC_TOO_MANY_REQUESTS) {
+ LOGGER.warn("rate limited, keep the local dimension [{}] configs unchanged.", dimensionsInfo);
+ queryConfigurationsResponse.setChanged(false);
+ return queryConfigurationsResponse;
} else if (httpResponse.getStatusCode() == HttpStatus.SC_BAD_REQUEST) {
throw new OperationException("Bad request for query configurations.");
} else {
@@ -118,11 +146,59 @@ public QueryConfigurationsResponse queryConfigurations(QueryConfigurationsReques
+ httpResponse.getContent());
}
} catch (IOException e) {
+ addressManager.recordFailState(address);
LOGGER.error("query configuration from {} failed, message={}", uri, e.getMessage());
throw new OperationException("", e);
}
}
+ private void recordAndSendUnAuthorizedEvent(HttpResponse response, String address) {
+ if (this.eventBus != null && response.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
+ LOGGER.warn("query configuration unauthorized from server [{}], message [{}]", address, response.getMessage());
+ addressManager.recordFailState(address);
+ this.eventBus.post(new UnAuthorizedOperationEvent(address));
+ } else {
+ addressManager.recordSuccessState(address);
+ }
+ }
+
+ /**
+ * Only the name of the new configuration item is printed.
+ * No log is printed when the configuration content is updated.
+ *
+ * @param dimension dimension
+ * @param configs configs
+ */
+ private void logConfigurationNames(String dimension, Map configs) {
+ if (CollectionUtils.isEmpty(configs)) {
+ return;
+ }
+ List configNames = dimensionConfigNames.get(dimension);
+ if (configNames == null) {
+ configNames = new ArrayList<>();
+ }
+ StringBuilder names = new StringBuilder();
+ for (String key : configs.keySet()) {
+ if (configNames.contains(key)) {
+ continue;
+ }
+ names.append(key).append(",");
+ configNames.add(key);
+ }
+ if (names.isEmpty()) {
+ return;
+ }
+ dimensionConfigNames.put(dimension, configNames);
+ String fileNames = names.substring(0, names.length() - 1);
+ LOGGER.info("pulling dimension [{}] configurations success, get config names: [{}].",
+ dimension, fileNames);
+ }
+
+ @Override
+ public void checkAddressAvailable(String address) {
+ ServiceCombServiceAvailableUtils.checkAddressAvailable(addressManager, address, httpTransport, ADDRESS_CHECK_PATH);
+ }
+
private String buildDimensionsInfo(QueryConfigurationsRequest request, boolean withVersion) {
String result =
request.getServiceName() + DEFAULT_APP_SEPARATOR
diff --git a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterConfigurationChangedEvent.java b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterConfigurationChangedEvent.java
new file mode 100644
index 00000000000..448c51a3d79
--- /dev/null
+++ b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterConfigurationChangedEvent.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.config.center.client;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * This event is fired when configuration changed of config center.
+ */
+public class ConfigCenterConfigurationChangedEvent {
+ private final Map added;
+
+ private final Map deleted;
+
+ private final Map updated;
+
+ private Set changed;
+
+ private ConfigCenterConfigurationChangedEvent(Map added, Map updated,
+ Map deleted) {
+ this.added = added;
+ this.deleted = deleted;
+ this.updated = updated;
+ this.changed = new HashSet<>();
+ this.changed.addAll(added.keySet());
+ this.changed.addAll(updated.keySet());
+ this.changed.addAll(deleted.keySet());
+ }
+
+ public static ConfigCenterConfigurationChangedEvent createIncremental(Map latest,
+ Map last) {
+ Map itemsCreated = new HashMap<>();
+ Map itemsDeleted = new HashMap<>();
+ Map itemsModified = new HashMap<>();
+
+ for (Map.Entry entry : latest.entrySet()) {
+ String itemKey = entry.getKey();
+ if (!last.containsKey(itemKey)) {
+ itemsCreated.put(itemKey, entry.getValue());
+ } else if (!Objects.equals(last.get(itemKey), latest.get(itemKey))) {
+ itemsModified.put(itemKey, entry.getValue());
+ }
+ }
+ for (String itemKey : last.keySet()) {
+ if (!latest.containsKey(itemKey)) {
+ itemsDeleted.put(itemKey, null);
+ }
+ }
+ ConfigCenterConfigurationChangedEvent event = ConfigCenterConfigurationChangedEvent
+ .createIncremental(itemsCreated, itemsModified, itemsDeleted);
+ return event;
+ }
+
+ public static ConfigCenterConfigurationChangedEvent createIncremental(Map added,
+ Map updated,
+ Map deleted) {
+ return new ConfigCenterConfigurationChangedEvent(added, updated, deleted);
+ }
+
+ public static ConfigCenterConfigurationChangedEvent createIncremental(Map updated) {
+ return new ConfigCenterConfigurationChangedEvent(new HashMap<>(), updated, new HashMap<>());
+ }
+
+ public final Map getAdded() {
+ return added;
+ }
+
+
+ public final Map getUpdated() {
+ return updated;
+ }
+
+
+ public final Map getDeleted() {
+ return deleted;
+ }
+
+ public final Set getChanged() {
+ return changed;
+ }
+}
diff --git a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterManager.java b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterManager.java
index 256a7bd3de4..7bfc43b4e05 100644
--- a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterManager.java
+++ b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterManager.java
@@ -17,12 +17,13 @@
package org.apache.servicecomb.config.center.client;
+import java.util.List;
import java.util.Map;
+import org.apache.servicecomb.config.center.client.model.ConfigCenterConfiguration;
import org.apache.servicecomb.config.center.client.model.QueryConfigurationsRequest;
import org.apache.servicecomb.config.center.client.model.QueryConfigurationsResponse;
import org.apache.servicecomb.config.common.ConfigConverter;
-import org.apache.servicecomb.config.common.ConfigurationChangedEvent;
import org.apache.servicecomb.http.client.task.AbstractTask;
import org.apache.servicecomb.http.client.task.Task;
import org.slf4j.Logger;
@@ -34,22 +35,26 @@ public class ConfigCenterManager extends AbstractTask {
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigCenterManager.class);
- private static final long POLL_INTERVAL = 15000;
-
- private ConfigCenterClient configCenterClient;
+ private final ConfigCenterClient configCenterClient;
private final EventBus eventBus;
private QueryConfigurationsRequest queryConfigurationsRequest;
- private ConfigConverter configConverter;
+ private final ConfigConverter configConverter;
+
+ private final ConfigCenterConfiguration configCenterConfiguration;
+
+ private final ConfigCenterAddressManager configCenterAddressManager;
- public ConfigCenterManager(ConfigCenterClient configCenterClient, EventBus eventBus,
- ConfigConverter configConverter) {
+ public ConfigCenterManager(ConfigCenterClient configCenterClient, EventBus eventBus, ConfigConverter configConverter,
+ ConfigCenterConfiguration configCenterConfiguration, ConfigCenterAddressManager configCenterAddressManager) {
super("config-center-configuration-task");
this.configCenterClient = configCenterClient;
this.eventBus = eventBus;
this.configConverter = configConverter;
+ this.configCenterConfiguration = configCenterConfiguration;
+ this.configCenterAddressManager = configCenterAddressManager;
}
public void setQueryConfigurationsRequest(QueryConfigurationsRequest queryConfigurationsRequest) {
@@ -58,6 +63,8 @@ public void setQueryConfigurationsRequest(QueryConfigurationsRequest queryConfig
public void startConfigCenterManager() {
this.startTask(new PollConfigurationTask(0));
+ schedulerCheckAddressAvailable("cc-addr-check", new CheckConfigCenterAddressTask(),
+ configCenterConfiguration.getRefreshIntervalInMillis());
}
class PollConfigurationTask implements Task {
@@ -70,19 +77,37 @@ public PollConfigurationTask(int failCount) {
@Override
public void execute() {
try {
- QueryConfigurationsResponse response = configCenterClient.queryConfigurations(queryConfigurationsRequest);
+ QueryConfigurationsResponse response = configCenterClient.queryConfigurations(queryConfigurationsRequest,
+ configCenterAddressManager.address());
if (response.isChanged()) {
queryConfigurationsRequest.setRevision(response.getRevision());
Map lastData = configConverter.updateData(response.getConfigurations());
- ConfigurationChangedEvent event = ConfigurationChangedEvent
+ ConfigCenterConfigurationChangedEvent event = ConfigCenterConfigurationChangedEvent
.createIncremental(configConverter.getCurrentData(), lastData);
- eventBus.post(event);
+ if (!event.getChanged().isEmpty()) {
+ eventBus.post(event);
+ }
}
- startTask(new BackOffSleepTask(POLL_INTERVAL, new PollConfigurationTask(0)));
+ startTask(
+ new BackOffSleepTask(configCenterConfiguration.getRefreshIntervalInMillis(), new PollConfigurationTask(0)));
} catch (Exception e) {
- LOGGER.error("get configurations from ConfigCenter failed, and will try again.", e);
+ LOGGER.warn("get configurations from ConfigCenter failed, and will try again, cause message: {}. current "
+ + "fail does not affect the obtained historical configuration.", e.getCause().getMessage());
startTask(new BackOffSleepTask(failCount + 1, new PollConfigurationTask(failCount + 1)));
}
}
}
+
+ class CheckConfigCenterAddressTask implements Runnable {
+ @Override
+ public void run() {
+ List isolationAddresses = configCenterAddressManager.getIsolationAddresses();
+ if (isolationAddresses.isEmpty()) {
+ return;
+ }
+ for (String address : isolationAddresses) {
+ configCenterClient.checkAddressAvailable(address);
+ }
+ }
+ }
}
diff --git a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterOperation.java b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterOperation.java
index 6cd726d47ba..919e9f30cd7 100644
--- a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterOperation.java
+++ b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterOperation.java
@@ -17,7 +17,7 @@
package org.apache.servicecomb.config.center.client;
-import org.apache.servicecomb.config.center.client.exception.OperationException;
+import org.apache.servicecomb.config.common.exception.OperationException;
import org.apache.servicecomb.config.center.client.model.QueryConfigurationsRequest;
import org.apache.servicecomb.config.center.client.model.QueryConfigurationsResponse;
@@ -25,8 +25,16 @@ public interface ConfigCenterOperation {
/**
* 根据查询条件查询配置项。
* @param request 查询的维度(project, application, serviceName, version) 和 revision 信息。
+ * @param address 查询的配置中心地址。
* @return 如果存在配置变更,返回全量的配置项, changed = true。 如果没有变更, 返回 null, changed = false,
* @throws OperationException If some problems happened to contact service center or non http 200 returned.
*/
- QueryConfigurationsResponse queryConfigurations(QueryConfigurationsRequest request);
+ QueryConfigurationsResponse queryConfigurations(QueryConfigurationsRequest request, String address);
+
+ /**
+ * Check config center isolation address available
+ *
+ * @param address isolation address
+ */
+ void checkAddressAvailable(String address);
}
diff --git a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/exception/OperationException.java b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/exception/OperationException.java
deleted file mode 100644
index c63d1bf39b3..00000000000
--- a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/exception/OperationException.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.servicecomb.config.center.client.exception;
-
-public class OperationException extends RuntimeException {
- private static final long serialVersionUID = 1L;
-
- public OperationException(String message) {
- super(message);
- }
-
- public OperationException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/model/ConfigCenterConfiguration.java b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/model/ConfigCenterConfiguration.java
new file mode 100644
index 00000000000..0556d14fced
--- /dev/null
+++ b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/model/ConfigCenterConfiguration.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.config.center.client.model;
+
+public class ConfigCenterConfiguration {
+
+ private long refreshIntervalInMillis = 15000;
+
+ public long getRefreshIntervalInMillis() {
+ return refreshIntervalInMillis;
+ }
+
+ public ConfigCenterConfiguration setRefreshIntervalInMillis(long refreshIntervalInMillis) {
+ this.refreshIntervalInMillis = refreshIntervalInMillis;
+ return this;
+ }
+}
diff --git a/clients/config-common/pom.xml b/clients/config-common/pom.xml
index 09567479057..ff10b993583 100644
--- a/clients/config-common/pom.xml
+++ b/clients/config-common/pom.xml
@@ -22,7 +22,7 @@
clientsorg.apache.servicecomb
- 2.6.0-SNAPSHOT
+ 3.4.0-SNAPSHOT4.0.0
@@ -41,4 +41,4 @@
-
\ No newline at end of file
+
diff --git a/clients/config-common/src/main/java/org/apache/servicecomb/config/common/ConfigConverter.java b/clients/config-common/src/main/java/org/apache/servicecomb/config/common/ConfigConverter.java
index 3caa641db0c..0d8973d8aeb 100644
--- a/clients/config-common/src/main/java/org/apache/servicecomb/config/common/ConfigConverter.java
+++ b/clients/config-common/src/main/java/org/apache/servicecomb/config/common/ConfigConverter.java
@@ -17,7 +17,7 @@
package org.apache.servicecomb.config.common;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
@@ -74,7 +74,7 @@ public Map updateData(Map rawData) {
private Map createFileSource(Object v) {
YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean();
- yamlFactory.setResources(new ByteArrayResource(v.toString().getBytes(Charset.forName("UTF-8"))));
+ yamlFactory.setResources(new ByteArrayResource(v.toString().getBytes(StandardCharsets.UTF_8)));
return propertiesToMap(yamlFactory.getObject());
}
diff --git a/clients/config-common/src/main/java/org/apache/servicecomb/config/common/ConfigurationChangedEvent.java b/clients/config-common/src/main/java/org/apache/servicecomb/config/common/ConfigurationChangedEvent.java
deleted file mode 100644
index a3514d004d4..00000000000
--- a/clients/config-common/src/main/java/org/apache/servicecomb/config/common/ConfigurationChangedEvent.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.servicecomb.config.common;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
-public class ConfigurationChangedEvent {
- private final Map added;
-
- private final Map deleted;
-
- private final Map updated;
-
- private final boolean changed;
-
- private Map complete;
-
- private ConfigurationChangedEvent(Map added, Map updated,
- Map deleted, boolean changed) {
- this.added = added;
- this.deleted = deleted;
- this.updated = updated;
- this.changed = changed;
- }
-
- public static ConfigurationChangedEvent createIncremental(Map latest, Map last) {
- Map itemsCreated = new HashMap<>();
- Map itemsDeleted = new HashMap<>();
- Map itemsModified = new HashMap<>();
- boolean changed = false;
-
- for (String itemKey : latest.keySet()) {
- if (!last.containsKey(itemKey)) {
- itemsCreated.put(itemKey, latest.get(itemKey));
- changed = true;
- } else if (!Objects.equals(last.get(itemKey), latest.get(itemKey))) {
- itemsModified.put(itemKey, latest.get(itemKey));
- changed = true;
- }
- }
- for (String itemKey : last.keySet()) {
- if (!latest.containsKey(itemKey)) {
- itemsDeleted.put(itemKey, null);
- changed = true;
- }
- }
- ConfigurationChangedEvent event = ConfigurationChangedEvent
- .createIncremental(itemsCreated, itemsModified, itemsDeleted, changed);
- event.complete = latest;
- return event;
- }
-
- private static ConfigurationChangedEvent createIncremental(Map added, Map updated,
- Map deleted, boolean changed) {
- return new ConfigurationChangedEvent(added, updated, deleted, changed);
- }
-
- public final Map getAdded() {
- return added;
- }
-
-
- public final Map getUpdated() {
- return updated;
- }
-
-
- public final Map getDeleted() {
- return deleted;
- }
-
- public final Map getComplete() {
- return complete;
- }
-
- public final boolean isChanged() {
- return changed;
- }
-}
diff --git a/clients/config-common/src/main/java/org/apache/servicecomb/config/common/exception/OperationException.java b/clients/config-common/src/main/java/org/apache/servicecomb/config/common/exception/OperationException.java
new file mode 100644
index 00000000000..f4e26b50505
--- /dev/null
+++ b/clients/config-common/src/main/java/org/apache/servicecomb/config/common/exception/OperationException.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.config.common.exception;
+
+public class OperationException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ public OperationException(String message) {
+ super(message);
+ }
+
+ public OperationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/clients/config-common/src/test/java/org/apache/servicecomb/config/common/TestConfigurationChangedEvent.java b/clients/config-common/src/test/java/org/apache/servicecomb/config/common/TestConfigurationChangedEvent.java
deleted file mode 100644
index bd11efde01c..00000000000
--- a/clients/config-common/src/test/java/org/apache/servicecomb/config/common/TestConfigurationChangedEvent.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.servicecomb.config.common;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-public class TestConfigurationChangedEvent {
- @Test
- public void testConfigurationChangedEvent() {
- Map before = new HashMap<>();
- Map after = new HashMap<>();
- before.put("updated", "1");
- before.put("deleted", "1");
- before.put("notChanged", null);
-
- after.put("added", 1);
- after.put("updated", 2);
- after.put("addedNull", null);
- after.put("notChanged", null);
-
- ConfigurationChangedEvent event = ConfigurationChangedEvent.createIncremental(after, before);
- Assert.assertEquals(2, event.getAdded().size());
- Assert.assertEquals(1, event.getDeleted().size());
- Assert.assertEquals(1, event.getUpdated().size());
- Assert.assertEquals(4, event.getComplete().size());
- Assert.assertEquals(true, event.isChanged());
- }
-}
diff --git a/clients/config-kie-client/pom.xml b/clients/config-kie-client/pom.xml
index f1f6d525876..30dac44ba53 100644
--- a/clients/config-kie-client/pom.xml
+++ b/clients/config-kie-client/pom.xml
@@ -22,7 +22,7 @@
clientsorg.apache.servicecomb
- 2.6.0-SNAPSHOT
+ 3.4.0-SNAPSHOT4.0.0
@@ -42,7 +42,13 @@
org.springframeworkspring-beans
+
+
+ com.google.guava
+ failureaccess
+ test
+
-
\ No newline at end of file
+
diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieClient.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieClient.java
index 5b64f2ded1e..b98a7d3b2a1 100644
--- a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieClient.java
+++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieClient.java
@@ -17,16 +17,23 @@
package org.apache.servicecomb.config.kie.client;
+import com.google.common.eventbus.EventBus;
+
import java.io.StringReader;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;
import org.apache.http.HttpStatus;
-import org.apache.servicecomb.config.kie.client.exception.OperationException;
+
+import org.apache.servicecomb.config.common.exception.OperationException;
import org.apache.servicecomb.config.kie.client.model.ConfigConstants;
import org.apache.servicecomb.config.kie.client.model.ConfigurationsRequest;
import org.apache.servicecomb.config.kie.client.model.ConfigurationsResponse;
@@ -39,15 +46,20 @@
import org.apache.servicecomb.http.client.common.HttpResponse;
import org.apache.servicecomb.http.client.common.HttpTransport;
import org.apache.servicecomb.http.client.common.HttpUtils;
+import org.apache.servicecomb.http.client.event.OperationEvents.UnAuthorizedOperationEvent;
+import org.apache.servicecomb.http.client.utils.ServiceCombServiceAvailableUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.io.ByteArrayResource;
+import org.springframework.util.CollectionUtils;
public class KieClient implements KieConfigOperation {
private static final Logger LOGGER = LoggerFactory.getLogger(KieClient.class);
+ private static final String ADDRESS_CHECK_PATH = "/v1/health";
+
protected HttpTransport httpTransport;
protected String revision = "0";
@@ -58,16 +70,24 @@ public class KieClient implements KieConfigOperation {
public static final String DEFAULT_KIE_API_VERSION = "v1";
+ private final Map> dimensionConfigNames = new HashMap<>();
+
+ private EventBus eventBus;
+
public KieClient(KieAddressManager addressManager, HttpTransport httpTransport, KieConfiguration kieConfiguration) {
this.httpTransport = httpTransport;
this.addressManager = addressManager;
this.kieConfiguration = kieConfiguration;
}
- @Override
- public ConfigurationsResponse queryConfigurations(ConfigurationsRequest request) {
- String url = buildUrl(request);
+ public void setEventBus(EventBus eventBus) {
+ this.eventBus = eventBus;
+ addressManager.setEventBus(eventBus);
+ }
+ @Override
+ public ConfigurationsResponse queryConfigurations(ConfigurationsRequest request, String address) {
+ String url = buildUrl(request, address);
try {
if (kieConfiguration.isEnableLongPolling()) {
url += "&wait=" + kieConfiguration.getPollingWaitInSeconds() + "s";
@@ -75,10 +95,12 @@ public ConfigurationsResponse queryConfigurations(ConfigurationsRequest request)
HttpRequest httpRequest = new HttpRequest(url, null, null, HttpRequest.GET);
HttpResponse httpResponse = httpTransport.doRequest(httpRequest);
+ recordAndSendUnAuthorizedEvent(httpResponse, address);
ConfigurationsResponse configurationsResponse = new ConfigurationsResponse();
if (httpResponse.getStatusCode() == HttpStatus.SC_OK) {
revision = httpResponse.getHeader("X-Kie-Revision");
KVResponse allConfigList = HttpUtils.deserialize(httpResponse.getContent(), KVResponse.class);
+ logConfigurationNames(request.getLabelsQuery(), allConfigList.getData());
Map configurations = getConfigByLabel(allConfigList);
configurationsResponse.setConfigurations(configurations);
configurationsResponse.setChanged(true);
@@ -92,18 +114,71 @@ public ConfigurationsResponse queryConfigurations(ConfigurationsRequest request)
configurationsResponse.setChanged(false);
return configurationsResponse;
}
+ if (httpResponse.getStatusCode() == HttpStatus.SC_TOO_MANY_REQUESTS) {
+ LOGGER.warn("rate limited, keep the local dimension [{}] configs unchanged.", request.getLabelsQuery());
+ configurationsResponse.setChanged(false);
+ return configurationsResponse;
+ }
throw new OperationException(
"read response failed. status:" + httpResponse.getStatusCode() + "; message:" +
httpResponse.getMessage() + "; content:" + httpResponse.getContent());
} catch (Exception e) {
+ addressManager.recordFailState(address);
LOGGER.error("query configuration from {} failed, message={}", url, e.getMessage());
throw new OperationException("read response failed. ", e);
}
}
- private String buildUrl(ConfigurationsRequest request) {
+ private void recordAndSendUnAuthorizedEvent(HttpResponse response, String address) {
+ if (this.eventBus != null && response.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
+ LOGGER.warn("query configuration unauthorized from server [{}], message [{}]", address, response.getMessage());
+ addressManager.recordFailState(address);
+ this.eventBus.post(new UnAuthorizedOperationEvent(address));
+ } else {
+ addressManager.recordSuccessState(address);
+ }
+ }
+
+ /**
+ * Only the name of the new configuration item is printed.
+ * No log is printed when the configuration content is updated.
+ *
+ * @param dimension dimension
+ * @param data configs-data
+ */
+ private void logConfigurationNames(String dimension, List data) {
+ if (CollectionUtils.isEmpty(data)) {
+ return;
+ }
+ List configNames = dimensionConfigNames.get(dimension);
+ if (configNames == null) {
+ configNames = new ArrayList<>();
+ }
+ StringBuilder names = new StringBuilder();
+ for (KVDoc doc : data) {
+ if (configNames.contains(doc.getKey())) {
+ continue;
+ }
+ names.append(doc.getKey()).append(",");
+ configNames.add(doc.getKey());
+ }
+ if (names.isEmpty()) {
+ return;
+ }
+ dimensionConfigNames.put(dimension, configNames);
+ String fileNames = names.substring(0, names.length() - 1);
+ LOGGER.info("pulling dimension [{}] configurations success, get config names: [{}].",
+ dimension, fileNames);
+ }
+
+ @Override
+ public void checkAddressAvailable(String address) {
+ ServiceCombServiceAvailableUtils.checkAddressAvailable(addressManager, address, httpTransport, ADDRESS_CHECK_PATH);
+ }
+
+ private String buildUrl(ConfigurationsRequest request, String currentAddress) {
StringBuilder sb = new StringBuilder();
- sb.append(addressManager.address());
+ sb.append(currentAddress);
sb.append("/");
sb.append(DEFAULT_KIE_API_VERSION);
sb.append("/");
@@ -121,6 +196,7 @@ private String buildUrl(ConfigurationsRequest request) {
private Map getConfigByLabel(KVResponse resp) {
Map resultMap = new HashMap<>();
resp.getData().stream()
+ .sorted(Comparator.comparing(KVDoc::getUpdateTime, Comparator.nullsFirst(Comparator.naturalOrder())))
.filter(doc -> doc.getStatus() == null || ConfigConstants.STATUS_ENABLED.equalsIgnoreCase(doc.getStatus()))
.map(this::processValueType)
.collect(Collectors.toList())
@@ -133,7 +209,7 @@ private Map processValueType(KVDoc kvDoc) {
try {
valueType = ValueType.valueOf(kvDoc.getValueType());
} catch (IllegalArgumentException e) {
- throw new OperationException("value type not support");
+ throw new OperationException("value type not support [" + kvDoc.getValue() + "]");
}
Properties properties = new Properties();
Map kvMap = new HashMap<>();
@@ -142,7 +218,7 @@ private Map processValueType(KVDoc kvDoc) {
case yml:
case yaml:
YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean();
- yamlFactory.setResources(new ByteArrayResource(kvDoc.getValue().getBytes()));
+ yamlFactory.setResources(new ByteArrayResource(kvDoc.getValue().getBytes(StandardCharsets.UTF_8)));
return toMap(yamlFactory.getObject());
case properties:
properties.load(new StringReader(kvDoc.getValue()));
@@ -154,7 +230,7 @@ private Map processValueType(KVDoc kvDoc) {
return kvMap;
}
} catch (Exception e) {
- LOGGER.error("read config failed");
+ LOGGER.error("read config failed", e);
}
return Collections.emptyMap();
}
diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieConfigManager.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieConfigManager.java
index 298a2c0ce6d..ed251613530 100644
--- a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieConfigManager.java
+++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieConfigManager.java
@@ -23,10 +23,10 @@
import java.util.concurrent.Executors;
import org.apache.servicecomb.config.common.ConfigConverter;
-import org.apache.servicecomb.config.common.ConfigurationChangedEvent;
import org.apache.servicecomb.config.kie.client.model.ConfigurationsRequest;
import org.apache.servicecomb.config.kie.client.model.ConfigurationsRequestFactory;
import org.apache.servicecomb.config.kie.client.model.ConfigurationsResponse;
+import org.apache.servicecomb.config.kie.client.model.KieAddressManager;
import org.apache.servicecomb.config.kie.client.model.KieConfiguration;
import org.apache.servicecomb.http.client.task.AbstractTask;
import org.apache.servicecomb.http.client.task.Task;
@@ -39,21 +39,22 @@ public class KieConfigManager extends AbstractTask {
private static final Logger LOGGER = LoggerFactory.getLogger(KieConfigManager.class);
- private static long POLL_INTERVAL = 1000;
+ private static final long LONG_POLLING_INTERVAL = 1000;
- private KieConfigOperation configKieClient;
+ private final KieConfigOperation configKieClient;
private final EventBus eventBus;
- private ConfigConverter configConverter;
+ private final ConfigConverter configConverter;
- private List configurationsRequests;
+ private final List configurationsRequests;
- private KieConfiguration kieConfiguration;
+ private final KieConfiguration kieConfiguration;
+
+ private final KieAddressManager kieAddressManager;
public KieConfigManager(KieConfigOperation configKieClient, EventBus eventBus,
- KieConfiguration kieConfiguration,
- ConfigConverter configConverter) {
+ KieConfiguration kieConfiguration, ConfigConverter configConverter, KieAddressManager kieAddressManager) {
super("config-center-configuration-task");
this.configurationsRequests = ConfigurationsRequestFactory.buildConfigurationRequests(kieConfiguration);
this.configurationsRequests.sort(ConfigurationsRequest::compareTo);
@@ -61,27 +62,44 @@ public KieConfigManager(KieConfigOperation configKieClient, EventBus eventBus,
this.eventBus = eventBus;
this.configConverter = configConverter;
this.kieConfiguration = kieConfiguration;
+ this.kieAddressManager = kieAddressManager;
}
public void firstPull() {
+ Map data = new HashMap<>();
try {
- Map data = new HashMap<>();
- this.configurationsRequests.forEach(r -> {
- r.setRevision(ConfigurationsRequest.INITIAL_REVISION);
- ConfigurationsResponse response = configKieClient.queryConfigurations(r);
- if (response.isChanged()) {
- r.setRevision(response.getRevision());
- r.setLastRawData(response.getConfigurations());
- data.putAll(response.getConfigurations());
- }
- });
- this.configConverter.updateData(data);
- } catch (RuntimeException e) {
+ firstQueryConfigurations(data);
+ } catch (Exception e) {
if (this.kieConfiguration.isFirstPullRequired()) {
throw e;
} else {
- LOGGER.warn("first pull failed, and ignore {}", e.getMessage());
+ LOGGER.warn("first pull failed!");
+ }
+ }
+ }
+
+ private void firstQueryConfigurations(Map data) {
+ for (int i = 0; i < 3;) {
+ String address = kieAddressManager.address();
+ try {
+ this.configurationsRequests.forEach(r -> {
+ r.setRevision(ConfigurationsRequest.INITIAL_REVISION);
+ ConfigurationsResponse response = configKieClient.queryConfigurations(r, address);
+ if (response.isChanged()) {
+ r.setRevision(response.getRevision());
+ r.setLastRawData(response.getConfigurations());
+ data.putAll(response.getConfigurations());
+ }
+ });
+ this.configConverter.updateData(data);
+ break;
+ } catch (Exception e) {
+ if (i == 2) {
+ throw e;
+ }
+ LOGGER.warn("firstQueryConfigurations failed, config address {} and ignore {}", address, e.getMessage());
}
+ i++;
}
}
@@ -90,9 +108,9 @@ private void onDataChanged() {
this.configurationsRequests.forEach(r -> latestData.putAll(r.getLastRawData()));
Map lastData = configConverter.updateData(latestData);
- ConfigurationChangedEvent event = ConfigurationChangedEvent
+ KieConfigurationChangedEvent event = KieConfigurationChangedEvent
.createIncremental(configConverter.getCurrentData(), lastData);
- if (event.isChanged()) {
+ if (!event.getChanged().isEmpty()) {
eventBus.post(event);
}
}
@@ -106,6 +124,8 @@ protected void initTaskPool(String taskName) {
public void startConfigKieManager() {
this.configurationsRequests.forEach((t) ->
this.startTask(new PollConfigurationTask(0, t)));
+ schedulerCheckAddressAvailable("kie-addr-check", new CheckKieAddressTask(),
+ kieConfiguration.getRefreshIntervalInMillis());
}
class PollConfigurationTask implements Task {
@@ -121,22 +141,39 @@ public PollConfigurationTask(int failCount, ConfigurationsRequest configurations
@Override
public void execute() {
try {
- ConfigurationsResponse response = configKieClient.queryConfigurations(configurationsRequest);
+ ConfigurationsResponse response = configKieClient.queryConfigurations(configurationsRequest,
+ kieAddressManager.address());
if (response.isChanged()) {
configurationsRequest.setRevision(response.getRevision());
configurationsRequest.setLastRawData(response.getConfigurations());
onDataChanged();
}
if (KieConfigManager.this.kieConfiguration.isEnableLongPolling()) {
- startTask(new BackOffSleepTask(POLL_INTERVAL, new PollConfigurationTask(0, this.configurationsRequest)));
+ startTask(
+ new BackOffSleepTask(LONG_POLLING_INTERVAL, new PollConfigurationTask(0, this.configurationsRequest)));
} else {
- startTask(new PollConfigurationTask(0, this.configurationsRequest));
+ startTask(new BackOffSleepTask(kieConfiguration.getRefreshIntervalInMillis(),
+ new PollConfigurationTask(0, this.configurationsRequest)));
}
} catch (Exception e) {
- LOGGER.error("get configurations from KieConfigCenter failed, and will try again.", e);
+ LOGGER.warn("get configurations from KieConfigCenter failed, and will try again, cause message: {}. current "
+ + "fail does not affect the obtained historical configuration.", e.getCause().getMessage());
startTask(
new BackOffSleepTask(failCount + 1, new PollConfigurationTask(failCount + 1, this.configurationsRequest)));
}
}
}
+
+ class CheckKieAddressTask implements Runnable {
+ @Override
+ public void run() {
+ List isolationAddresses = kieAddressManager.getIsolationAddresses();
+ if (isolationAddresses.isEmpty()) {
+ return;
+ }
+ for (String address : isolationAddresses) {
+ configKieClient.checkAddressAvailable(address);
+ }
+ }
+ }
}
diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieConfigOperation.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieConfigOperation.java
index 1079a1fa576..135ad0c220a 100644
--- a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieConfigOperation.java
+++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieConfigOperation.java
@@ -17,7 +17,7 @@
package org.apache.servicecomb.config.kie.client;
-import org.apache.servicecomb.config.kie.client.exception.OperationException;
+import org.apache.servicecomb.config.common.exception.OperationException;
import org.apache.servicecomb.config.kie.client.model.ConfigurationsRequest;
import org.apache.servicecomb.config.kie.client.model.ConfigurationsResponse;
@@ -26,8 +26,16 @@ public interface KieConfigOperation {
/**
* 根据查询条件查询配置项。
* @param request 查询的维度(project, application, serviceName, version) 和 revision 信息。
+ * @param address 查询的配置中心地址。
* @return 如果存在配置变更,返回全量的配置项, changed = true。 如果没有变更, 返回 null, changed = false,
* @throws OperationException If some problems happened to contact service center or non http 200 returned.
*/
- ConfigurationsResponse queryConfigurations(ConfigurationsRequest request);
+ ConfigurationsResponse queryConfigurations(ConfigurationsRequest request, String address);
+
+ /**
+ * Check kie isolation address available
+ *
+ * @param address isolation address
+ */
+ void checkAddressAvailable(String address);
}
diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieConfigurationChangedEvent.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieConfigurationChangedEvent.java
new file mode 100644
index 00000000000..0e22c17e8b9
--- /dev/null
+++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieConfigurationChangedEvent.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.config.kie.client;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * This event is fired when configuration changed of kie.
+ */
+public class KieConfigurationChangedEvent {
+ private final Map added;
+
+ private final Map deleted;
+
+ private final Map updated;
+
+ private Set changed;
+
+ private KieConfigurationChangedEvent(Map added, Map updated,
+ Map deleted) {
+ this.added = added;
+ this.deleted = deleted;
+ this.updated = updated;
+ this.changed = new HashSet<>();
+ this.changed.addAll(added.keySet());
+ this.changed.addAll(updated.keySet());
+ this.changed.addAll(deleted.keySet());
+ }
+
+ public static KieConfigurationChangedEvent createIncremental(Map latest, Map last) {
+ Map itemsCreated = new HashMap<>();
+ Map itemsDeleted = new HashMap<>();
+ Map itemsModified = new HashMap<>();
+
+ for (Map.Entry entry : latest.entrySet()) {
+ String itemKey = entry.getKey();
+ if (!last.containsKey(itemKey)) {
+ itemsCreated.put(itemKey, entry.getValue());
+ } else if (!Objects.equals(last.get(itemKey), latest.get(itemKey))) {
+ itemsModified.put(itemKey, entry.getValue());
+ }
+ }
+ for (String itemKey : last.keySet()) {
+ if (!latest.containsKey(itemKey)) {
+ itemsDeleted.put(itemKey, null);
+ }
+ }
+ KieConfigurationChangedEvent event = KieConfigurationChangedEvent
+ .createIncremental(itemsCreated, itemsModified, itemsDeleted);
+ return event;
+ }
+
+ public static KieConfigurationChangedEvent createIncremental(Map added, Map updated,
+ Map deleted) {
+ return new KieConfigurationChangedEvent(added, updated, deleted);
+ }
+
+ public static KieConfigurationChangedEvent createIncremental(Map updated) {
+ return new KieConfigurationChangedEvent(new HashMap<>(), updated, new HashMap<>());
+ }
+
+ public final Map getAdded() {
+ return added;
+ }
+
+
+ public final Map getUpdated() {
+ return updated;
+ }
+
+
+ public final Map getDeleted() {
+ return deleted;
+ }
+
+ public final Set getChanged() {
+ return changed;
+ }
+}
diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/exception/OperationException.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/exception/OperationException.java
deleted file mode 100644
index fa14be96687..00000000000
--- a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/exception/OperationException.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.servicecomb.config.kie.client.exception;
-
-public class OperationException extends RuntimeException {
- private static final long serialVersionUID = 1L;
-
- public OperationException(String message) {
- super(message);
- }
-
- public OperationException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsRequest.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsRequest.java
index cbf964766d0..b22f7ecaa23 100644
--- a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsRequest.java
+++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsRequest.java
@@ -17,10 +17,11 @@
package org.apache.servicecomb.config.kie.client.model;
+import java.util.HashMap;
import java.util.Map;
public class ConfigurationsRequest implements Comparable {
- public static final String INITIAL_REVISION = "0";
+ public static final String INITIAL_REVISION = "-1";
private int order;
@@ -30,7 +31,7 @@ public class ConfigurationsRequest implements Comparable
private String labelsQuery;
- private Map lastRawData;
+ private Map lastRawData = new HashMap<>();
public int getOrder() {
return order;
@@ -79,6 +80,7 @@ public ConfigurationsRequest setLastRawData(Map lastRawData) {
@Override
public int compareTo(ConfigurationsRequest o) {
+ // Higher priority, query the last
return o.getOrder() - this.order;
}
}
diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsRequestFactory.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsRequestFactory.java
index dd766aac83b..20c6ba3bacb 100644
--- a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsRequestFactory.java
+++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsRequestFactory.java
@@ -30,11 +30,15 @@ public class ConfigurationsRequestFactory {
private static final String KEY_SERVICE = "service";
- private static final int SERVICE_ORDER = 100;
+ private static final String KEY_VERSION = "version";
- private static final int APP_ORDER = 200;
+ private static final int CUSTOM_ORDER = 100;
- private static final int CUSTOM_ORDER = 300;
+ private static final int VERSION_ORDER = 200;
+
+ private static final int SERVICE_ORDER = 300;
+
+ private static final int APP_ORDER = 400;
public static List buildConfigurationRequests(KieConfiguration configuration) {
List result = new ArrayList<>();
@@ -44,6 +48,9 @@ public static List buildConfigurationRequests(KieConfigur
if (configuration.isEnableServiceConfig()) {
result.add(createServiceConfigurationsRequest(configuration));
}
+ if (configuration.isEnableVersionConfig()) {
+ result.add(createVersionConfigurationsRequest(configuration));
+ }
if (configuration.isEnableCustomConfig()) {
result.add(createCustomConfigurationsRequest(configuration));
}
@@ -67,6 +74,16 @@ private static ConfigurationsRequest createServiceConfigurationsRequest(KieConfi
buildLabelQueryItem(KEY_ENVIRONMENT, configuration.getEnvironment())));
}
+ private static ConfigurationsRequest createVersionConfigurationsRequest(KieConfiguration configuration) {
+ return new ConfigurationsRequest()
+ .setOrder(VERSION_ORDER)
+ .setWithExact(true)
+ .setLabelsQuery(buildLabelQuery(buildLabelQueryItem(KEY_APP, configuration.getAppName()),
+ buildLabelQueryItem(KEY_SERVICE, configuration.getServiceName()),
+ buildLabelQueryItem(KEY_ENVIRONMENT, configuration.getEnvironment()),
+ buildLabelQueryItem(KEY_VERSION, configuration.getVersion())));
+ }
+
private static ConfigurationsRequest createCustomConfigurationsRequest(KieConfiguration configuration) {
return new ConfigurationsRequest()
.setOrder(CUSTOM_ORDER)
diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KVDoc.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KVDoc.java
index d5d00c3ad63..3059a581c61 100644
--- a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KVDoc.java
+++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KVDoc.java
@@ -35,7 +35,7 @@ public class KVDoc {
@JsonAlias("label_id")
private String labelId;
- private Map labels = new HashMap();
+ private Map labels = new HashMap<>();
private String value;
@@ -44,6 +44,9 @@ public class KVDoc {
private String status;
+ @JsonAlias("update_time")
+ private long updateTime;
+
public String getStatus() {
return status;
}
@@ -115,4 +118,12 @@ public void setValue(String value) {
public String getValueType() {
return valueType;
}
+
+ public long getUpdateTime() {
+ return updateTime;
+ }
+
+ public void setUpdateTime(long updateTime) {
+ this.updateTime = updateTime;
+ }
}
diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KieAddressManager.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KieAddressManager.java
index dde884ff4b4..d8c069ee9b1 100644
--- a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KieAddressManager.java
+++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KieAddressManager.java
@@ -17,30 +17,23 @@
package org.apache.servicecomb.config.kie.client.model;
-import java.util.ArrayList;
import java.util.List;
-public class KieAddressManager {
- private final List addresses;
+import org.apache.servicecomb.http.client.common.AbstractAddressManager;
+import org.apache.servicecomb.http.client.event.RefreshEndpointEvent;
- private int index = 0;
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
- public KieAddressManager(List addresses) {
- this.addresses = new ArrayList<>(addresses.size());
- this.addresses.addAll(addresses);
- }
-
- public String address() {
- synchronized (this) {
- this.index++;
- if (this.index >= addresses.size()) {
- this.index = 0;
- }
- return addresses.get(index);
- }
+public class KieAddressManager extends AbstractAddressManager {
+
+ public KieAddressManager(List addresses, EventBus eventBus, String region, String availableZone) {
+ super(addresses, region, availableZone);
+ eventBus.register(this);
}
- public boolean sslEnabled() {
- return address().startsWith("https://");
+ @Subscribe
+ public void onRefreshEndpointEvent(RefreshEndpointEvent event) {
+ refreshEndpoint(event, RefreshEndpointEvent.KIE_NAME);
}
}
diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KieConfiguration.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KieConfiguration.java
index 8bf93c1cc21..9c75f2d09c2 100644
--- a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KieConfiguration.java
+++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KieConfiguration.java
@@ -22,6 +22,8 @@ public class KieConfiguration {
private int pollingWaitInSeconds;
+ private int refreshIntervalInMillis = 15000;
+
private String project;
private String appName;
@@ -30,10 +32,14 @@ public class KieConfiguration {
private String environment;
+ private String version;
+
private boolean enableAppConfig;
private boolean enableServiceConfig;
+ private boolean enableVersionConfig;
+
private boolean enableCustomConfig;
private String customLabelValue;
@@ -123,6 +129,15 @@ public KieConfiguration setEnableLongPolling(boolean enableLongPolling) {
return this;
}
+ public boolean isEnableVersionConfig() {
+ return enableVersionConfig;
+ }
+
+ public KieConfiguration setEnableVersionConfig(boolean enableVersionConfig) {
+ this.enableVersionConfig = enableVersionConfig;
+ return this;
+ }
+
public int getPollingWaitInSeconds() {
return pollingWaitInSeconds;
}
@@ -149,4 +164,22 @@ public KieConfiguration setFirstPullRequired(boolean firstPullRequired) {
this.firstPullRequired = firstPullRequired;
return this;
}
+
+ public int getRefreshIntervalInMillis() {
+ return refreshIntervalInMillis;
+ }
+
+ public KieConfiguration setRefreshIntervalInMillis(int refreshIntervallnMillis) {
+ this.refreshIntervalInMillis = refreshIntervallnMillis;
+ return this;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public KieConfiguration setVersion(String version) {
+ this.version = version;
+ return this;
+ }
}
diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/LabelDocResponse.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/LabelDocResponse.java
index 62359902919..2b9e055de0f 100644
--- a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/LabelDocResponse.java
+++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/LabelDocResponse.java
@@ -27,7 +27,7 @@ public class LabelDocResponse {
@JsonAlias("label_id")
private String labelId;
- private Map labels = new HashMap();
+ private Map labels = new HashMap<>();
public String getLabelId() {
return labelId;
diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ValueType.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ValueType.java
index b38a1e28f8e..23cbce3b367 100644
--- a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ValueType.java
+++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ValueType.java
@@ -24,5 +24,6 @@ public enum ValueType {
string,
text,
json,
- properties
+ properties,
+ xml
}
diff --git a/clients/config-kie-client/src/test/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsRequestTest.java b/clients/config-kie-client/src/test/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsRequestTest.java
new file mode 100644
index 00000000000..47c152fa1df
--- /dev/null
+++ b/clients/config-kie-client/src/test/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsRequestTest.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.config.kie.client.model;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Map;
+
+class ConfigurationsRequestTest {
+
+ @Test
+ void getLastRawData() {
+ ConfigurationsRequest configurationsRequest = new ConfigurationsRequest();
+ Map lastRawData = configurationsRequest.getLastRawData();
+ Assertions.assertEquals(lastRawData.size(), 0);
+ }
+}
diff --git a/clients/config-kie-client/src/test/java/org/apache/servicecomb/config/kie/client/model/KieAddressManagerTest.java b/clients/config-kie-client/src/test/java/org/apache/servicecomb/config/kie/client/model/KieAddressManagerTest.java
new file mode 100644
index 00000000000..c8bf1f57a29
--- /dev/null
+++ b/clients/config-kie-client/src/test/java/org/apache/servicecomb/config/kie/client/model/KieAddressManagerTest.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.config.kie.client.model;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.servicecomb.http.client.event.RefreshEndpointEvent;
+
+import com.google.common.eventbus.EventBus;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class KieAddressManagerTest {
+
+ private static final List addresses = new ArrayList<>();
+
+ private static KieAddressManager addressManager1;
+
+ @Test
+ public void kieAddressManagerTest() throws NoSuchFieldException, IllegalAccessException {
+ addresses.add("http://127.0.0.1:30103");
+ addresses.add("https://127.0.0.2:30103");
+ addressManager1 = new KieAddressManager(addresses, new EventBus(), "", "");
+ Field addressManagerField = addressManager1.getClass().getSuperclass().getDeclaredField("index");
+ addressManagerField.setAccessible(true);
+ addressManagerField.set(addressManager1, 0);
+
+ Assertions.assertNotNull(addressManager1);
+
+ List addresses = addressManager1.getAddresses();
+ Assertions.assertEquals(2, addresses.size());
+ Assertions.assertEquals("http://127.0.0.1:30103", addresses.get(0));
+
+ Assertions.assertEquals("https://127.0.0.2:30103", addressManager1.address());
+ Assertions.assertEquals("http://127.0.0.1:30103", addressManager1.address());
+ }
+
+ @Test
+ public void onRefreshEndpointEvent() {
+ List addressAZ = new ArrayList<>();
+ addressAZ.add("http://127.0.0.3:30100");
+ List addressRG = new ArrayList<>();
+ addressRG.add("http://127.0.0.4:30100");
+ Map> zoneAndRegion = new HashMap<>();
+ zoneAndRegion.put("sameZone", addressAZ);
+ zoneAndRegion.put("sameRegion", addressRG);
+ addressManager1 = new KieAddressManager(addresses, new EventBus(), "", "");
+ RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, "KIE");
+ addressManager1.refreshEndpoint(event, "KIE");
+
+ List availableZone = addressManager1.getAvailableZone();
+ Assertions.assertEquals("http://127.0.0.3:30100", availableZone.get(0));
+
+ List availableRegion = addressManager1.getAvailableRegion();
+ Assertions.assertEquals("http://127.0.0.4:30100", availableRegion.get(0));
+ }
+}
diff --git a/clients/dashboard-client/pom.xml b/clients/dashboard-client/pom.xml
new file mode 100644
index 00000000000..fb40407b82a
--- /dev/null
+++ b/clients/dashboard-client/pom.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+ clients
+ org.apache.servicecomb
+ 3.4.0-SNAPSHOT
+
+ 4.0.0
+
+ dashboard-client
+ ServiceComb::Clients::Dashboard Client
+
+
+
+ org.apache.servicecomb
+ http-client-common
+
+
+ org.springframework
+ spring-beans
+
+
+
+ com.google.guava
+ failureaccess
+ test
+
+
+
+
+
diff --git a/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/DashboardAddressManager.java b/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/DashboardAddressManager.java
new file mode 100644
index 00000000000..6897e02acd4
--- /dev/null
+++ b/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/DashboardAddressManager.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.dashboard.client;
+
+
+import java.util.List;
+
+import org.apache.servicecomb.http.client.common.AbstractAddressManager;
+import org.apache.servicecomb.http.client.event.RefreshEndpointEvent;
+
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+
+
+public class DashboardAddressManager extends AbstractAddressManager {
+
+ public DashboardAddressManager(List addresses, EventBus eventBus, String region, String availableZone) {
+ super(addresses, region, availableZone);
+ eventBus.register(this);
+ }
+
+ @Subscribe
+ public void onRefreshEndpointEvent(RefreshEndpointEvent event) {
+ refreshEndpoint(event, RefreshEndpointEvent.CSE_MONITORING_NAME);
+ }
+}
diff --git a/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/DashboardClient.java b/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/DashboardClient.java
new file mode 100644
index 00000000000..2fe84429cb7
--- /dev/null
+++ b/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/DashboardClient.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.dashboard.client;
+
+import org.apache.http.HttpStatus;
+import org.apache.servicecomb.dashboard.client.model.MonitorData;
+import org.apache.servicecomb.http.client.common.HttpRequest;
+import org.apache.servicecomb.http.client.common.HttpResponse;
+import org.apache.servicecomb.http.client.common.HttpTransport;
+import org.apache.servicecomb.http.client.common.HttpUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DashboardClient implements DashboardOperation {
+ private static final Logger LOGGER = LoggerFactory.getLogger(DashboardClient.class);
+
+ protected HttpTransport httpTransport;
+
+ private final DashboardAddressManager addressManager;
+
+ public DashboardClient(DashboardAddressManager addressManager, HttpTransport httpTransport) {
+ this.httpTransport = httpTransport;
+ this.addressManager = addressManager;
+ }
+
+ @Override
+ public void sendData(String url, MonitorData data) {
+ String address = addressManager.address();
+ try {
+ HttpRequest httpRequest = new HttpRequest(address + url, null, HttpUtils.serialize(data), HttpRequest.POST);
+ HttpResponse httpResponse = httpTransport.doRequest(httpRequest);
+ if (httpResponse.getStatusCode() != HttpStatus.SC_OK) {
+ LOGGER.error("send data to [{}] failed, status code [{}], message [{}]", url, httpResponse.getStatusCode()
+ , httpResponse.getContent());
+ }
+ } catch (Exception e) {
+ LOGGER.error("send data to [{}] failed", url, e);
+ }
+ }
+}
diff --git a/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/DashboardOperation.java b/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/DashboardOperation.java
new file mode 100644
index 00000000000..733ebfc4676
--- /dev/null
+++ b/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/DashboardOperation.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.dashboard.client;
+
+import org.apache.servicecomb.dashboard.client.model.MonitorData;
+
+public interface DashboardOperation {
+ void sendData(String url, MonitorData monitorData);
+}
diff --git a/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/data/InterfaceInfo.java b/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/model/InterfaceInfo.java
similarity index 98%
rename from huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/data/InterfaceInfo.java
rename to clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/model/InterfaceInfo.java
index 23a35f0089d..1a72c8fe747 100644
--- a/huawei-cloud/dashboard/src/main/java/org/apache/servicecomb/huaweicloud/dashboard/monitor/data/InterfaceInfo.java
+++ b/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/model/InterfaceInfo.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.servicecomb.huaweicloud.dashboard.monitor.data;
+package org.apache.servicecomb.dashboard.client.model;
public class InterfaceInfo {
private String name;
diff --git a/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/model/MonitorData.java b/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/model/MonitorData.java
new file mode 100644
index 00000000000..d02facd5daa
--- /dev/null
+++ b/clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/model/MonitorData.java
@@ -0,0 +1,188 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.dashboard.client.model;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class MonitorData {
+ public static final double PERCENTAGE_995 = 99.5;
+
+ public static final double PERCENTAGE_99 = 99;
+
+ public static final double PERCENTAGE_90 = 90;
+
+ public static final double PERCENTAGE_75 = 75;
+
+ public static final double PERCENTAGE_50 = 50;
+
+ public static final double PERCENTAGE_25 = 25;
+
+ public static final double PERCENTAGE_5 = 5;
+
+ public static final int SCALE_VAL = 1;
+
+ public static final double DEFAULT_SUCCESS_RATE = 1.0d;
+
+ public static final int CONVERSION = 1000;
+
+ private String appId;
+
+ private String version;
+
+ private String name;
+
+ private String serviceId;
+
+ private String environment;
+
+ private String instance;
+
+ private String instanceId;
+
+ private int thread;
+
+ private double cpu;
+
+ private double loadAverage;
+
+ private long uptime;
+
+ private Map memory;
+
+ private List interfaces = new ArrayList<>();
+
+ private Map customs;
+
+ public void addInterfaceInfo(InterfaceInfo interfaceInfo) {
+ interfaces.add(interfaceInfo);
+ }
+
+ public String getAppId() {
+ return appId;
+ }
+
+ public void setAppId(String appId) {
+ this.appId = appId;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getServiceId() {
+ return serviceId;
+ }
+
+ public void setServiceId(String serviceId) {
+ this.serviceId = serviceId;
+ }
+
+ public String getInstance() {
+ return instance;
+ }
+
+ public void setInstance(String instance) {
+ this.instance = instance;
+ }
+
+ public String getInstanceId() {
+ return instanceId;
+ }
+
+ public void setInstanceId(String instanceId) {
+ this.instanceId = instanceId;
+ }
+
+ public int getThreadCount() {
+ return thread;
+ }
+
+ public void setThreadCount(int threadCount) {
+ this.thread = threadCount;
+ }
+
+ public double getCpu() {
+ return cpu;
+ }
+
+ public void setCpu(double cpu) {
+ this.cpu = cpu;
+ }
+
+ public double getLoadAverage() {
+ return loadAverage;
+ }
+
+ public void setLoadAverage(double loadAverage) {
+ this.loadAverage = loadAverage;
+ }
+
+ public long getUptime() {
+ return uptime;
+ }
+
+ public void setUptime(long uptime) {
+ this.uptime = uptime;
+ }
+
+ public Map getMemory() {
+ return memory;
+ }
+
+ public void setMemory(Map memory) {
+ this.memory = memory;
+ }
+
+ public List getInterfaces() {
+ return interfaces;
+ }
+
+ public void setInterfaces(List interfaces) {
+ this.interfaces = interfaces;
+ }
+
+ public Map getCustoms() {
+ return customs;
+ }
+
+ public void setCustoms(Map customs) {
+ this.customs = customs;
+ }
+
+ public String getEnvironment() {
+ return environment;
+ }
+
+ public void setEnvironment(String environment) {
+ this.environment = environment;
+ }
+}
diff --git a/clients/dashboard-client/src/test/java/org/apache/servicecomb/dashboard/client/AddressManagerTest.java b/clients/dashboard-client/src/test/java/org/apache/servicecomb/dashboard/client/AddressManagerTest.java
new file mode 100644
index 00000000000..fdb7a23922b
--- /dev/null
+++ b/clients/dashboard-client/src/test/java/org/apache/servicecomb/dashboard/client/AddressManagerTest.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.dashboard.client;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.servicecomb.http.client.event.RefreshEndpointEvent;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import com.google.common.eventbus.EventBus;
+
+class AddressManagerTest {
+
+ private static final List addresses = new ArrayList<>();
+
+ private static DashboardAddressManager addressManager1;
+
+ @Test
+ public void kieAddressManagerTest() throws IllegalAccessException, NoSuchFieldException {
+ addresses.add("http://127.0.0.1:30103");
+ addresses.add("https://127.0.0.2:30103");
+ addressManager1 = new DashboardAddressManager(addresses, new EventBus(), "", "");
+ Field addressManagerField = addressManager1.getClass().getSuperclass().getDeclaredField("index");
+ addressManagerField.setAccessible(true);
+ addressManagerField.set(addressManager1, 0);
+
+ Assertions.assertNotNull(addressManager1);
+
+ List addresses = addressManager1.getAddresses();
+ Assertions.assertEquals(2, addresses.size());
+ Assertions.assertEquals("http://127.0.0.1:30103", addresses.get(0));
+
+ Assertions.assertEquals("https://127.0.0.2:30103", addressManager1.address());
+ Assertions.assertEquals("http://127.0.0.1:30103", addressManager1.address());
+ }
+
+ @Test
+ public void onRefreshEndpointEvent() {
+ List addressAZ = new ArrayList<>();
+ addressAZ.add("http://127.0.0.3:30100");
+ List addressRG = new ArrayList<>();
+ addressRG.add("http://127.0.0.4:30100");
+ Map> zoneAndRegion = new HashMap<>();
+ zoneAndRegion.put("sameZone", addressAZ);
+ zoneAndRegion.put("sameRegion", addressRG);
+ addressManager1 = new DashboardAddressManager(addresses, new EventBus(), "", "");
+ RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, "CseMonitoring");
+ addressManager1.refreshEndpoint(event, "CseMonitoring");
+
+ List availableZone = addressManager1.getAvailableZone();
+ Assertions.assertEquals("http://127.0.0.3:30100", availableZone.get(0));
+
+ List availableRegion = addressManager1.getAvailableRegion();
+ Assertions.assertEquals("http://127.0.0.4:30100", availableRegion.get(0));
+ }
+}
diff --git a/clients/http-client-common/pom.xml b/clients/http-client-common/pom.xml
index b53d66f3bd4..51d982e470c 100644
--- a/clients/http-client-common/pom.xml
+++ b/clients/http-client-common/pom.xml
@@ -22,7 +22,7 @@
clientsorg.apache.servicecomb
- 2.6.0-SNAPSHOT
+ 3.4.0-SNAPSHOT4.0.0
@@ -71,17 +71,5 @@
org.java-websocketJava-WebSocket
-
-
- junit
- junit
- test
-
-
-
- org.mockito
- mockito-core
- test
-
-
\ No newline at end of file
+
diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/AbstractAddressManager.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/AbstractAddressManager.java
new file mode 100644
index 00000000000..3c5d6214be8
--- /dev/null
+++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/AbstractAddressManager.java
@@ -0,0 +1,348 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.http.client.common;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.servicecomb.http.client.event.EngineConnectChangedEvent;
+import org.apache.servicecomb.http.client.event.RefreshEndpointEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.CollectionUtils;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.eventbus.EventBus;
+
+public class AbstractAddressManager {
+ private static final Logger LOGGER = LoggerFactory.getLogger(AbstractAddressManager.class);
+
+ public static final String DEFAULT_PROJECT = "default";
+
+ public static final String V4_PREFIX = "/v4/";
+
+ private static final String V3_PREFIX = "/v3/";
+
+ private static final String ZONE = "availableZone";
+
+ private static final String REGION = "region";
+
+ private static final int ISOLATION_THRESHOLD = 3;
+
+ private volatile List addresses = new ArrayList<>();
+
+ // when all addresses are isolation, it will use this for polling.
+ private final List defaultAddress = new ArrayList<>();
+
+ private final List defaultIsolationAddress = new ArrayList<>();
+
+ private int index;
+
+ private String projectName;
+
+ // recording continuous times of failure of an address.
+ private final Map addressFailureStatus = new ConcurrentHashMap<>();
+
+ private volatile List availableZone = new ArrayList<>();
+
+ private final List isolationZoneAddress = new ArrayList<>();
+
+ private volatile List availableRegion = new ArrayList<>();
+
+ private final List isolationRegionAddress = new ArrayList<>();
+
+ private volatile boolean addressAutoRefreshed = false;
+
+ private final Object lock = new Object();
+
+ private final Random random = new Random();
+
+ private EventBus eventBus;
+
+ public AbstractAddressManager(List addresses, String ownRegion, String ownAvailableZone) {
+ this.projectName = DEFAULT_PROJECT;
+ parseAndInitAddresses(addresses, ownRegion, ownAvailableZone, false);
+ this.index = !addresses.isEmpty() ? getRandomIndex() : 0;
+ }
+
+ /**
+ * address support config with region/availableZone info, to enable engine affinity calls during startup
+ * address may be like:
+ * https://192.168.20.13:30110?region=region1&availableZone=az
+ * https://192.168.20.13:30100?region=region1&availableZone=az
+ * When address have no datacenter information, roundRobin using address
+ *
+ * @param addresses engine addresses
+ * @param ownRegion microservice region
+ * @param ownAvailableZone microservice zone
+ * @param isFormat is need format
+ */
+ private void parseAndInitAddresses(List addresses, String ownRegion, String ownAvailableZone,
+ boolean isFormat) {
+ if (CollectionUtils.isEmpty(addresses)) {
+ return;
+ }
+ List tempList = new ArrayList<>();
+ addressAutoRefreshed = addresses.stream().anyMatch(addr -> addr.contains(ZONE) || addr.contains(REGION));
+ for (String address : addresses) {
+ // Compatible IpPortManager init address is 127.0.0.1:30100
+ if (!address.startsWith("http")) {
+ tempList.add(address);
+ continue;
+ }
+ URLEndPoint endpoint = new URLEndPoint(address);
+ tempList.add(endpoint.toString());
+ buildAffinityAddress(endpoint, ownRegion, ownAvailableZone);
+ }
+ this.addresses.addAll(isFormat ? this.transformAddress(tempList) : tempList);
+ this.defaultAddress.addAll(isFormat ? this.transformAddress(tempList) : tempList);
+ }
+
+ private void buildAffinityAddress(URLEndPoint endpoint, String ownRegion, String ownAvailableZone) {
+ if (addressAutoRefreshed) {
+ if (regionAndAZMatch(ownRegion, ownAvailableZone, endpoint.getFirst(REGION), endpoint.getFirst(ZONE))) {
+ availableZone.add(endpoint.toString());
+ } else {
+ availableRegion.add(endpoint.toString());
+ }
+ }
+ }
+
+ private boolean regionAndAZMatch(String ownRegion, String ownAvailableZone, String engineRegion,
+ String engineAvailableZone) {
+ return ownRegion.equalsIgnoreCase(engineRegion) && ownAvailableZone.equals(engineAvailableZone);
+ }
+
+ public AbstractAddressManager(String projectName, List addresses, String ownRegion, String ownAvailableZone) {
+ this.projectName = StringUtils.isEmpty(projectName) ? DEFAULT_PROJECT : projectName;
+ parseAndInitAddresses(addresses, ownRegion, ownAvailableZone, true);
+ this.index = !addresses.isEmpty() ? getRandomIndex() : 0;
+ }
+
+ private int getRandomIndex() {
+ return random.nextInt(addresses.size());
+ }
+
+ public void refreshEndpoint(RefreshEndpointEvent event, String key) {
+ if (null == event || !event.getName().equals(key)) {
+ return;
+ }
+
+ availableZone = event.getSameZone().stream().map(this::normalizeUri).collect(Collectors.toList());
+ availableRegion = event.getSameRegion().stream().map(this::normalizeUri).collect(Collectors.toList());
+ addressAutoRefreshed = true;
+ }
+
+ protected String normalizeUri(String endpoint) {
+ return new URLEndPoint(endpoint).toString();
+ }
+
+ @VisibleForTesting
+ Map getAddressFailureStatus() {
+ return addressFailureStatus;
+ }
+
+ public List getAddresses() {
+ return addresses;
+ }
+
+ public List getAvailableZone() {
+ return availableZone;
+ }
+
+ public List getAvailableRegion() {
+ return availableRegion;
+ }
+
+ public String formatUrl(String url, boolean absoluteUrl, String address) {
+ return absoluteUrl ? address + url : formatAddress(address) + url;
+ }
+
+ public boolean sslEnabled() {
+ return address().startsWith("https://");
+ }
+
+ protected List transformAddress(List addresses) {
+ return addresses.stream().map(this::formatAddress).collect(Collectors.toList());
+ }
+
+ protected String formatAddress(String address) {
+ try {
+ return getUrlPrefix(address) + HttpUtils.encodeURLParam(this.projectName);
+ } catch (Exception e) {
+ throw new IllegalStateException("not possible");
+ }
+ }
+
+ protected String getUrlPrefix(String address) {
+ return address + V3_PREFIX;
+ }
+
+ public String address() {
+ if (!addressAutoRefreshed) {
+ return getDefaultAddress();
+ } else {
+ return getAvailableZoneAddress();
+ }
+ }
+
+ private String getDefaultAddress() {
+ if (!addresses.isEmpty()) {
+ return getCurrentAddress(addresses);
+ }
+ LOGGER.warn("all addresses are isolation, please check server status.");
+ // when all addresses are isolation, it will use all default address for polling.
+ return getCurrentAddress(defaultAddress);
+ }
+
+ private String getAvailableZoneAddress() {
+ List zoneOrRegionAddress = getZoneOrRegionAddress();
+ if (!zoneOrRegionAddress.isEmpty()) {
+ return getCurrentAddress(zoneOrRegionAddress);
+ }
+ LOGGER.warn("all auto discovery addresses are isolation, please check server status.");
+ // when all available address are isolation, it will use config addresses for polling.
+ return getCurrentAddress(addresses);
+ }
+
+ private String getCurrentAddress(List addresses) {
+ synchronized (this) {
+ this.index++;
+ if (this.index >= addresses.size()) {
+ this.index = 0;
+ }
+ return addresses.get(index);
+ }
+ }
+
+ private List getZoneOrRegionAddress() {
+ List results = new ArrayList<>();
+ if (!availableZone.isEmpty()) {
+ results.addAll(availableZone);
+ } else {
+ results.addAll(availableRegion);
+ }
+ return results;
+ }
+
+ public void recordSuccessState(String address) {
+ resetFailureStatus(address);
+ if (addressAutoRefreshed) {
+ if (isolationZoneAddress.remove(address)) {
+ LOGGER.warn("restore same region address [{}]", address);
+ if (eventBus != null && availableZone.isEmpty()) {
+ eventBus.post(new EngineConnectChangedEvent());
+ }
+ availableZone.add(address);
+ return;
+ }
+ if (isolationRegionAddress.remove(address)) {
+ LOGGER.warn("restore same zone address [{}]", address);
+ availableRegion.add(address);
+ }
+ return;
+ }
+ if (defaultIsolationAddress.remove(address)) {
+ LOGGER.warn("restore default address [{}]", address);
+ addresses.add(address);
+ }
+ }
+
+ public void resetFailureStatus(String address) {
+ addressFailureStatus.put(address, 0);
+ }
+
+ public void recordFailState(String address) {
+ synchronized (lock) {
+ if (!addressFailureStatus.containsKey(address)) {
+ addressFailureStatus.put(address, 1);
+ return;
+ }
+ int number = addressFailureStatus.get(address) + 1;
+ if (number < ISOLATION_THRESHOLD) {
+ addressFailureStatus.put(address, number);
+ } else {
+ removeAddress(address);
+ }
+ }
+ }
+
+ //Query whether the current address belongs to the same AZ or the same region through AZMap,
+ // and delete it from the record. At the same time, add records in history and cache
+ @VisibleForTesting
+ void removeAddress(String address) {
+ if (!addressAutoRefreshed) {
+ if (addresses.remove(address)) {
+ LOGGER.warn("isolation default address [{}]", address);
+ defaultIsolationAddress.add(address);
+ }
+ return;
+ }
+ if (availableZone.remove(address)) {
+ LOGGER.warn("isolation same zone address [{}]", address);
+ isolationZoneAddress.add(address);
+ if (eventBus != null && availableZone.isEmpty() && !availableRegion.isEmpty()) {
+ eventBus.post(new EngineConnectChangedEvent());
+ }
+ return;
+ }
+ if (availableRegion.remove(address)) {
+ LOGGER.warn("isolation same region address [{}]", address);
+ isolationRegionAddress.add(address);
+ }
+ }
+
+ public void setEventBus(EventBus eventBus) {
+ this.eventBus = eventBus;
+ }
+
+ public List getIsolationAddresses() {
+ List isolationAddresses = new ArrayList<>(defaultIsolationAddress);
+ isolationAddresses.addAll(isolationZoneAddress);
+ isolationAddresses.addAll(isolationRegionAddress);
+ return isolationAddresses;
+ }
+
+ public String compareAndGetAddress(String host) {
+ for (String address : defaultAddress) {
+ if (isAddressHostSame(address, host)) {
+ return address;
+ }
+ }
+ return "";
+ }
+
+ private boolean isAddressHostSame(String address, String host) {
+ if (StringUtils.isEmpty(host)) {
+ return false;
+ }
+ try {
+ URI uri = new URI(address);
+ return host.equals(uri.getHost());
+ } catch (Exception e) {
+ LOGGER.warn("Exception occurred while constructing URI using the address [{}]", address);
+ }
+ return false;
+ }
+}
diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpRequest.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpRequest.java
index 08d7a06d681..35e14df06c1 100644
--- a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpRequest.java
+++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpRequest.java
@@ -41,11 +41,11 @@ public class HttpRequest {
private String method;
- private String url;
+ private final String url;
private Map headers;
- private String content;
+ private final String content;
public HttpRequest(String url, Map headers, String content, String method) {
this.url = url;
diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpTransportImpl.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpTransportImpl.java
index 429f5bd7f38..507d8d1c556 100644
--- a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpTransportImpl.java
+++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpTransportImpl.java
@@ -18,17 +18,21 @@
package org.apache.servicecomb.http.client.common;
import java.io.IOException;
+import java.net.URI;
import java.util.Map;
import org.apache.http.client.HttpClient;
import org.apache.http.util.EntityUtils;
import org.apache.servicecomb.foundation.auth.SignRequest;
import org.apache.servicecomb.http.client.auth.RequestAuthHeaderProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Created by on 2019/10/16.
*/
public class HttpTransportImpl implements HttpTransport {
+ private static final Logger LOGGER = LoggerFactory.getLogger(HttpTransportImpl.class);
private static final String HEADER_CONTENT_TYPE = "Content-Type";
@@ -38,7 +42,7 @@ public class HttpTransportImpl implements HttpTransport {
private Map globalHeaders;
- private RequestAuthHeaderProvider requestAuthHeaderProvider;
+ private final RequestAuthHeaderProvider requestAuthHeaderProvider;
public HttpTransportImpl(HttpClient httpClient, RequestAuthHeaderProvider requestAuthHeaderProvider) {
this.httpClient = httpClient;
@@ -87,7 +91,7 @@ public HttpResponse doRequest(HttpRequest httpRequest) throws IOException {
globalHeaders.forEach(httpRequest::addHeader);
}
- httpRequest.getHeaders().putAll(requestAuthHeaderProvider.loadAuthHeader(createSignRequest()));
+ httpRequest.getHeaders().putAll(requestAuthHeaderProvider.loadAuthHeader(createSignRequest(httpRequest.getUrl())));
//get Http response
org.apache.http.HttpResponse response = httpClient.execute(httpRequest.getRealRequest());
@@ -98,13 +102,20 @@ public HttpResponse doRequest(HttpRequest httpRequest) throws IOException {
response.getAllHeaders());
}
- private static SignRequest createSignRequest() {
- // Now the implementations do not process SignRequest, so return null. Maybe future will use it.
- return null;
+ private static SignRequest createSignRequest(String url) {
+ try {
+ URI uri = URI.create(url);
+ SignRequest signRequest = new SignRequest();
+ signRequest.setEndpoint(uri);
+ return signRequest;
+ } catch (Exception e) {
+ LOGGER.error("create signRequest failed!", e);
+ return null;
+ }
}
@Override
public void addHeaders(Map headers) {
this.globalHeaders = headers;
}
-}
\ No newline at end of file
+}
diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpUtils.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpUtils.java
index 37d5c207473..5f259cc3053 100644
--- a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpUtils.java
+++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpUtils.java
@@ -18,6 +18,7 @@
package org.apache.servicecomb.http.client.common;
import java.io.IOException;
+import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
@@ -55,7 +56,14 @@ public static String encodeURLParam(String value) throws IOException {
if (value == null) {
return "";
}
- return URLEncoder.encode(value, "UTF-8");
+ return URLEncoder.encode(value, StandardCharsets.UTF_8);
+ }
+
+ public static String decodeURLParam(String value) throws IOException {
+ if (value == null) {
+ return null;
+ }
+ return URLDecoder.decode(value, StandardCharsets.UTF_8);
}
public static String sha256Encode(String key, String data) throws Exception {
diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/MessageObjectMapper.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/MessageObjectMapper.java
index 3cb7f21ac7d..4eb85472643 100644
--- a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/MessageObjectMapper.java
+++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/MessageObjectMapper.java
@@ -33,7 +33,8 @@ public MessageObjectMapper() {
disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
// no view annotations shouldn't be included in JSON
- disable(MapperFeature.DEFAULT_VIEW_INCLUSION);
+ this._deserializationConfig = this._deserializationConfig.without(MapperFeature.DEFAULT_VIEW_INCLUSION);
+ this._serializationConfig = this._serializationConfig.without(MapperFeature.DEFAULT_VIEW_INCLUSION);
disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
enable(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS);
enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/SSLSocketFactoryExt.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/SSLSocketFactoryExt.java
index cd9f9413f82..db5f18afee7 100644
--- a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/SSLSocketFactoryExt.java
+++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/SSLSocketFactoryExt.java
@@ -24,11 +24,11 @@
import java.net.UnknownHostException;
public class SSLSocketFactoryExt extends SSLSocketFactory {
- private SSLSocketFactory sslSocketFactory;
+ private final SSLSocketFactory sslSocketFactory;
- private String host;
+ private final String host;
- private int port;
+ private final int port;
public SSLSocketFactoryExt(SSLSocketFactory factory, String host, int port) {
this.sslSocketFactory = factory;
diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/URLEndPoint.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/URLEndPoint.java
new file mode 100644
index 00000000000..e3e53bad06a
--- /dev/null
+++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/URLEndPoint.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.http.client.common;
+
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URLEncodedUtils;
+
+public class URLEndPoint {
+ private static final String SSL_ENABLED_KEY = "sslEnabled";
+
+ private static final String HTTP_KEY = "http://";
+
+ private static final String HTTPS_KEY = "https://";
+
+ private final boolean sslEnabled;
+
+ private final Map> queries;
+
+ private final String hostOrIp;
+
+ private final int port;
+
+ public URLEndPoint(String endpoint) {
+ URI uri = URI.create(endpoint);
+ hostOrIp = uri.getHost();
+ if (uri.getPort() < 0) {
+ throw new IllegalArgumentException("port not specified.");
+ }
+ port = uri.getPort();
+ queries = splitQuery(uri);
+ if (endpoint.contains(HTTPS_KEY)) {
+ sslEnabled = true;
+ } else {
+ sslEnabled = Boolean.parseBoolean(getFirst(SSL_ENABLED_KEY));
+ }
+ }
+
+ public static Map> splitQuery(URI uri) {
+ final Map> queryPairs = new LinkedHashMap<>();
+ List pairs = URLEncodedUtils.parse(uri, StandardCharsets.UTF_8);
+ for (NameValuePair pair : pairs) {
+ List list = queryPairs.computeIfAbsent(pair.getName(), name -> new ArrayList<>());
+ list.add(pair.getValue());
+ }
+ return queryPairs;
+ }
+
+ public String getFirst(String key) {
+ List values = queries.get(key);
+ if (values == null) {
+ return null;
+ }
+ return values.get(0);
+ }
+
+ @Override
+ public String toString() {
+ if (sslEnabled) {
+ return HTTPS_KEY + hostOrIp + ":" + port;
+ }
+ return HTTP_KEY + hostOrIp + ":" + port;
+ }
+}
diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/WebSocketTransport.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/WebSocketTransport.java
index 7d36e288527..ab630c609be 100644
--- a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/WebSocketTransport.java
+++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/WebSocketTransport.java
@@ -31,7 +31,7 @@
public class WebSocketTransport extends WebSocketClient {
public static final int CONNECT_TIMEOUT = 5000;
- private WebSocketListener webSocketListener;
+ private final WebSocketListener webSocketListener;
public WebSocketTransport(String serverUri, HttpConfiguration.SSLProperties sslProperties,
Map headers, WebSocketListener webSocketListener)
diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/EngineConnectChangedEvent.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/EngineConnectChangedEvent.java
new file mode 100644
index 00000000000..b2029f5c38c
--- /dev/null
+++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/EngineConnectChangedEvent.java
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.http.client.event;
+
+public class EngineConnectChangedEvent {
+}
diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/OperationEvents.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/OperationEvents.java
similarity index 79%
rename from clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/OperationEvents.java
rename to clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/OperationEvents.java
index 62274519ea4..69896f750ec 100644
--- a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/OperationEvents.java
+++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/OperationEvents.java
@@ -15,10 +15,18 @@
* limitations under the License.
*/
-package org.apache.servicecomb.service.center.client;
+package org.apache.servicecomb.http.client.event;
public abstract class OperationEvents {
public static class UnAuthorizedOperationEvent extends OperationEvents {
+ private final String address;
+ public UnAuthorizedOperationEvent(String address) {
+ this.address = address;
+ }
+
+ public String getAddress() {
+ return address;
+ }
}
}
diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/RefreshEndpointEvent.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/RefreshEndpointEvent.java
new file mode 100644
index 00000000000..4e4f1be648e
--- /dev/null
+++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/RefreshEndpointEvent.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.http.client.event;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class RefreshEndpointEvent {
+
+ public static final String SERVICE_CENTER_NAME = "SERVICECENTER";
+
+ public static final String KIE_NAME = "KIE";
+
+ public static final String CONFIG_CENTER_NAME = "CseConfigCenter";
+
+ public static final String CSE_MONITORING_NAME = "CseMonitoring";
+
+ private static final String SAME_ZONE = "sameZone";
+
+ private static final String SAME_REGION = "sameRegion";
+
+ private Map> zoneAndRegion = new HashMap<>();
+
+ private String name;
+
+ public RefreshEndpointEvent(Map> zoneAndRegion, String name) {
+ this.zoneAndRegion = zoneAndRegion;
+ this.name = name;
+ }
+
+ public List getSameZone() {
+ if (zoneAndRegion.get(SAME_ZONE).isEmpty()) {
+ return new ArrayList<>();
+ }
+ return zoneAndRegion.get(SAME_ZONE);
+ }
+
+ public List getSameRegion() {
+ if (zoneAndRegion.get(SAME_REGION).isEmpty()) {
+ return new ArrayList<>();
+ }
+ return zoneAndRegion.get(SAME_REGION);
+ }
+
+ public Map> getZoneAndRegion() {
+ return zoneAndRegion;
+ }
+
+ public void setZoneAndRegion(Map> zoneAndRegion) {
+ this.zoneAndRegion = zoneAndRegion;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/task/AbstractTask.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/task/AbstractTask.java
index c33c04a96f8..cc10ae8e142 100644
--- a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/task/AbstractTask.java
+++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/task/AbstractTask.java
@@ -20,23 +20,25 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AbstractTask {
public class BackOffSleepTask implements Task {
- final long base = 3000;
+ private static final long BASE = 3000;
- final long max = 10 * 60 * 10000;
+ private static final long MAX = 10 * 60 * 1000;
long waitTime;
Task nextTask;
public BackOffSleepTask(int failedCount, Task nextTask) {
- this.waitTime = failedCount * failedCount * base;
+ this.waitTime = failedCount * failedCount * BASE;
this.nextTask = nextTask;
}
@@ -47,7 +49,7 @@ public BackOffSleepTask(long waitTime, Task nextTask) {
@Override
public void execute() {
- long time = Math.min(max, waitTime);
+ long time = Math.min(MAX, waitTime);
try {
Thread.sleep(time);
} catch (InterruptedException e) {
@@ -63,19 +65,25 @@ public void execute() {
private volatile boolean running = true;
+ public static AtomicInteger taskCounter = new AtomicInteger(0);
+
+ private ScheduledExecutorService addrCheckExecutor;
+
protected AbstractTask(String taskName) {
initTaskPool(taskName);
- Runtime.getRuntime().addShutdownHook(new Thread(taskName + "-shutdown-hook") {
- @Override
- public void run() {
- AbstractTask.this.stop();
- }
- });
+ Runtime.getRuntime().addShutdownHook(new Thread(AbstractTask.this::stop, taskName + "-shutdown-hook"));
}
protected void initTaskPool(String taskName) {
this.taskPool = Executors.newSingleThreadExecutor((task) ->
- new Thread(task, taskName));
+ new Thread(task, taskName + "-" + taskCounter.getAndIncrement()));
+ }
+
+ protected void schedulerCheckAddressAvailable(String taskName, Runnable task, long delayTime) {
+ if (addrCheckExecutor == null) {
+ addrCheckExecutor = Executors.newScheduledThreadPool(1, (t) -> new Thread(t, taskName));
+ }
+ addrCheckExecutor.scheduleWithFixedDelay(task, delayTime, delayTime, TimeUnit.MILLISECONDS);
}
protected void startTask(Task task) {
@@ -101,6 +109,10 @@ public void stop() {
running = false;
this.taskPool.shutdown();
this.taskPool.awaitTermination(10, TimeUnit.SECONDS);
+ if (addrCheckExecutor != null) {
+ this.addrCheckExecutor.shutdown();
+ this.addrCheckExecutor.awaitTermination(10, TimeUnit.SECONDS);
+ }
} catch (InterruptedException e) {
LOGGER.warn("tasks not shutdown in time {}", e.getMessage());
}
diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/utils/ServiceCombServiceAvailableUtils.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/utils/ServiceCombServiceAvailableUtils.java
new file mode 100644
index 00000000000..9139e65f96a
--- /dev/null
+++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/utils/ServiceCombServiceAvailableUtils.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.http.client.utils;
+
+import org.apache.http.HttpStatus;
+import org.apache.servicecomb.http.client.common.AbstractAddressManager;
+import org.apache.servicecomb.http.client.common.HttpRequest;
+import org.apache.servicecomb.http.client.common.HttpResponse;
+import org.apache.servicecomb.http.client.common.HttpTransport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+public class ServiceCombServiceAvailableUtils {
+ private static final Logger LOGGER = LoggerFactory.getLogger(ServiceCombServiceAvailableUtils.class);
+
+ public static void checkAddressAvailable(AbstractAddressManager addressManager, String address,
+ HttpTransport httpTransport, String path) {
+ String formatUrl = addressManager.formatUrl(path, true, address);
+ HttpRequest httpRequest = new HttpRequest(formatUrl, null, null, HttpRequest.GET);
+ try {
+ HttpResponse response = httpTransport.doRequest(httpRequest);
+ if (response.getStatusCode() == HttpStatus.SC_OK) {
+ addressManager.recordSuccessState(address);
+ return;
+ }
+
+ // old server does not provide the check api, using TCP checks whether the server is ready.
+ if (response.getStatusCode() == HttpStatus.SC_NOT_FOUND && telnetCheckAddress(address)) {
+ LOGGER.warn("[{}] path does not provide, tcp check address ready!", path);
+ addressManager.recordSuccessState(address);
+ }
+ } catch (IOException e) {
+ LOGGER.error("check isolation address [{}] available error!", address);
+ }
+ }
+
+ private static boolean telnetCheckAddress(String address) {
+ URI ipPort = parseIpPortFromURI(address);
+ if (ipPort == null) {
+ return false;
+ }
+ try (Socket s = new Socket()) {
+ s.connect(new InetSocketAddress(ipPort.getHost(), ipPort.getPort()), 3000);
+ return true;
+ } catch (IOException e) {
+ LOGGER.warn("ping endpoint {} failed, It will be quarantined again.", address);
+ }
+ return false;
+ }
+
+ private static URI parseIpPortFromURI(String address) {
+ try {
+ return new URI(address);
+ } catch (URISyntaxException e) {
+ LOGGER.error("build uri error with address [{}].", address);
+ return null;
+ }
+ }
+}
diff --git a/clients/http-client-common/src/test/java/org/apache/servicecomb/http/client/common/AbstractAddressManagerTest.java b/clients/http-client-common/src/test/java/org/apache/servicecomb/http/client/common/AbstractAddressManagerTest.java
new file mode 100644
index 00000000000..b14d6827cb8
--- /dev/null
+++ b/clients/http-client-common/src/test/java/org/apache/servicecomb/http/client/common/AbstractAddressManagerTest.java
@@ -0,0 +1,328 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.http.client.common;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.servicecomb.http.client.event.RefreshEndpointEvent;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class AbstractAddressManagerTest {
+
+ private static final List addresses = new ArrayList<>();
+
+ private static AbstractAddressManager addressManager1;
+
+ private static AbstractAddressManager addressManager2;
+
+ private static AbstractAddressManager addressManager3;
+
+ @BeforeEach
+ public void setUp() throws NoSuchFieldException, IllegalAccessException {
+ addresses.add("http://127.0.0.1:30103");
+ addresses.add("https://127.0.0.2:30103");
+ addressManager1 = new AbstractAddressManager(addresses, "", "");
+ addressManager2 = new AbstractAddressManager("project", addresses, "", "");
+ addressManager3 = new AbstractAddressManager(null, addresses, "", "");
+ Field addressManagerField = addressManager1.getClass().getDeclaredField("index");
+ addressManagerField.setAccessible(true);
+ addressManagerField.set(addressManager1, 0);
+ addressManagerField = addressManager2.getClass().getDeclaredField("index");
+ addressManagerField.setAccessible(true);
+ addressManagerField.set(addressManager2, 0);
+ addressManagerField = addressManager3.getClass().getDeclaredField("index");
+ addressManagerField.setAccessible(true);
+ addressManagerField.set(addressManager3, 0);
+ }
+
+ @AfterEach
+ public void tearDown() {
+ addresses.clear();
+ addressManager1 = null;
+ addressManager2 = null;
+ addressManager3 = null;
+ }
+
+ @Test
+ public void abstractAddressManagerTest() {
+ Assertions.assertNotNull(addressManager1);
+ Assertions.assertNotNull(addressManager2);
+ Assertions.assertNotNull(addressManager3);
+
+ Assertions.assertEquals("https://127.0.0.2:30103", addressManager1.address());
+ Assertions.assertEquals("http://127.0.0.1:30103", addressManager1.address());
+ }
+
+ @Test
+ public void recordStateTest() throws ExecutionException {
+ List addressAZ = new ArrayList<>();
+ addressAZ.add("http://127.0.0.3:30100");
+ List addressRG = new ArrayList<>();
+ addressRG.add("http://127.0.0.4:30100");
+ Map> zoneAndRegion = new HashMap<>();
+ zoneAndRegion.put("sameZone", addressAZ);
+ zoneAndRegion.put("sameRegion", addressRG);
+ RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, "TEST");
+ AbstractAddressManager addressManager = new AbstractAddressManager(addresses, "", "") {};
+
+ addressManager.refreshEndpoint(event, "TEST");
+
+ String address = "http://127.0.0.3:30100";
+ addressManager.recordFailState(address);
+
+ Assertions.assertEquals("http://127.0.0.3:30100", addressManager.address());
+
+ addressManager.recordFailState(address);
+ Assertions.assertEquals("http://127.0.0.3:30100", addressManager.address());
+
+ // test fail 2 times ,it will not be isolated
+ addressManager.resetFailureStatus(address);
+ Assertions.assertEquals("http://127.0.0.3:30100", addressManager.address());
+
+ // test recodeStatus times
+ Map recodeStatus = addressManager.getAddressFailureStatus();
+ Assertions.assertEquals(0, (int) recodeStatus.get("http://127.0.0.3:30100"));
+
+ // test fail 3 times ,it will be isolated
+ addressManager.recordFailState(address);
+ addressManager.recordFailState(address);
+ addressManager.recordFailState(address);
+ Assertions.assertEquals("http://127.0.0.4:30100", addressManager.address());
+
+ // test restore isolation
+ addressManager.recordSuccessState("http://127.0.0.3:30100");
+ Assertions.assertEquals("http://127.0.0.3:30100", addressManager.address());
+ Assertions.assertEquals("http://127.0.0.3:30100", addressManager.address());
+ }
+
+
+ @Test
+ public void testMultipleThread() throws Exception {
+
+ AbstractAddressManager addressManager = new AbstractAddressManager(addresses, "", "");
+ String address = "http://127.0.0.3:30100";
+
+ CountDownLatch latch = new CountDownLatch(2);
+ for (int i = 0; i < 2; i++) {
+ new Thread(() -> {
+ addressManager.recordFailState(address);
+ latch.countDown();
+ }).start();
+ }
+ latch.await(30, TimeUnit.SECONDS);
+
+ Map recodeStatus = addressManager.getAddressFailureStatus();
+ Assertions.assertEquals(2, (int) recodeStatus.get("http://127.0.0.3:30100"));
+ }
+
+ @Test
+ public void addressForOnlyDefaultTest() {
+ Assertions.assertEquals("https://127.0.0.2:30103", addressManager1.address());
+ Assertions.assertEquals("http://127.0.0.1:30103", addressManager1.address());
+
+ Assertions.assertEquals("https://127.0.0.2:30103/v3/project", addressManager2.address());
+ Assertions.assertEquals("http://127.0.0.1:30103/v3/project", addressManager2.address());
+
+ Assertions.assertEquals("https://127.0.0.2:30103/v3/default", addressManager3.address());
+ Assertions.assertEquals("http://127.0.0.1:30103/v3/default", addressManager3.address());
+ }
+
+ @Test
+ public void addressForOnlyAzTest() {
+ List addressAZ = new ArrayList<>();
+ addressAZ.add("http://127.0.0.1:30100");
+ addressAZ.add("https://127.0.0.2:30100");
+ addressAZ.add("rest://127.0.0.1:30100?sslEnabled=true");
+ addressAZ.add("rest://127.0.0.2:30100?sslEnabled=false");
+
+ Map> zoneAndRegion = new HashMap<>();
+ zoneAndRegion.put("sameZone", addressAZ);
+ zoneAndRegion.put("sameRegion", new ArrayList<>());
+ RefreshEndpointEvent event1 = new RefreshEndpointEvent(zoneAndRegion, "TEST");
+ addressManager1.refreshEndpoint(event1, "TEST");
+
+ Assertions.assertEquals("https://127.0.0.2:30100", addressManager1.address());
+ Assertions.assertEquals("https://127.0.0.1:30100", addressManager1.address());
+ Assertions.assertEquals("http://127.0.0.2:30100", addressManager1.address());
+ Assertions.assertEquals("http://127.0.0.1:30100", addressManager1.address());
+ Assertions.assertEquals("https://127.0.0.2:30100", addressManager1.address());
+ }
+
+ @Test
+ public void addressForOnlyRegionTest() {
+ List addressRG = new ArrayList<>();
+ addressRG.add("rest://127.0.0.5:30100?sslEnabled=true");
+ addressRG.add("rest://127.0.0.6:30100");
+ addressRG.add("http://127.0.0.7:30100");
+ addressRG.add("https://127.0.0.8:30100");
+ Map> zoneAndRegion = new HashMap<>();
+ zoneAndRegion.put("sameZone", new ArrayList<>());
+ zoneAndRegion.put("sameRegion", addressRG);
+ RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, "TEST");
+ addressManager1.refreshEndpoint(event, "TEST");
+
+ Assertions.assertEquals("http://127.0.0.6:30100", addressManager1.address());
+ Assertions.assertEquals("http://127.0.0.7:30100", addressManager1.address());
+ Assertions.assertEquals("https://127.0.0.8:30100", addressManager1.address());
+ Assertions.assertEquals("https://127.0.0.5:30100", addressManager1.address());
+ Assertions.assertEquals("http://127.0.0.6:30100", addressManager1.address());
+ }
+
+ @Test
+ public void addressForAzAndRegionTest() {
+ List addressAZ = new ArrayList<>();
+ addressAZ.add("rest://127.0.0.1:30100?sslEnabled=true");
+ addressAZ.add("https://127.0.0.2:30100");
+ List addressRG = new ArrayList<>();
+ addressRG.add("rest://127.0.0.3:30100?sslEnabled=true");
+ addressRG.add("https://127.0.0.4:30100");
+ Map> zoneAndRegion = new HashMap<>();
+ zoneAndRegion.put("sameZone", addressAZ);
+ zoneAndRegion.put("sameRegion", addressRG);
+ RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, "TEST");
+ addressManager1.refreshEndpoint(event, "TEST");
+
+ Assertions.assertEquals("https://127.0.0.2:30100", addressManager1.address());
+ Assertions.assertEquals("https://127.0.0.1:30100", addressManager1.address());
+ Assertions.assertEquals("https://127.0.0.2:30100", addressManager1.address());
+
+ addressManager1.removeAddress("https://127.0.0.2:30100");
+ addressManager1.removeAddress("https://127.0.0.1:30100");
+ Assertions.assertEquals("https://127.0.0.3:30100", addressManager1.address());
+ Assertions.assertEquals("https://127.0.0.4:30100", addressManager1.address());
+ Assertions.assertEquals("https://127.0.0.3:30100", addressManager1.address());
+
+ addressManager1.removeAddress("https://127.0.0.4:30100");
+ addressManager1.removeAddress("https://127.0.0.3:30100");
+ Assertions.assertEquals("https://127.0.0.2:30103", addressManager1.address());
+ Assertions.assertEquals("http://127.0.0.1:30103", addressManager1.address());
+ Assertions.assertEquals("https://127.0.0.2:30103", addressManager1.address());
+ }
+
+ @Test
+ public void sslEnabledTest() {
+ Assertions.assertTrue(addressManager1.sslEnabled());
+ Assertions.assertFalse(addressManager1.sslEnabled());
+ Assertions.assertTrue(addressManager1.sslEnabled());
+
+ Assertions.assertTrue(addressManager2.sslEnabled());
+ Assertions.assertFalse(addressManager2.sslEnabled());
+ Assertions.assertTrue(addressManager2.sslEnabled());
+ }
+
+ @Test
+ public void transformAddressTest() {
+ List address = new ArrayList<>();
+ address.add("rest://127.0.0.1:30100?sslEnabled=true");
+ address.add("rest://127.0.0.2:30100");
+ address.add("http://127.0.0.3:30100");
+ address.add("https://127.0.0.4:30100");
+
+ List formAddress = addressManager2.transformAddress(address);
+
+ Assertions.assertEquals("rest://127.0.0.1:30100?sslEnabled=true/v3/project", formAddress.get(0));
+ Assertions.assertEquals("rest://127.0.0.2:30100/v3/project", formAddress.get(1));
+ Assertions.assertEquals("http://127.0.0.3:30100/v3/project", formAddress.get(2));
+ Assertions.assertEquals("https://127.0.0.4:30100/v3/project", formAddress.get(3));
+
+ formAddress = addressManager3.transformAddress(address);
+ Assertions.assertEquals("rest://127.0.0.1:30100?sslEnabled=true/v3/default", formAddress.get(0));
+ Assertions.assertEquals("rest://127.0.0.2:30100/v3/default", formAddress.get(1));
+ Assertions.assertEquals("http://127.0.0.3:30100/v3/default", formAddress.get(2));
+ Assertions.assertEquals("https://127.0.0.4:30100/v3/default", formAddress.get(3));
+ }
+
+ @Test
+ public void getUrlPrefixTest() {
+ Assertions.assertEquals("http://127.0.0.3:30100/v3/", addressManager2.getUrlPrefix("http://127.0.0.3:30100"));
+ Assertions.assertEquals("http://127.0.0.3:30100/v3/", addressManager3.getUrlPrefix("http://127.0.0.3:30100"));
+ }
+
+ @Test
+ public void refreshEndpointTest() {
+ List addressAZ = new ArrayList<>();
+ addressAZ.add("rest://127.0.0.1:30100");
+ Map> zoneAndRegion = new HashMap<>();
+ zoneAndRegion.put("sameZone", addressAZ);
+ zoneAndRegion.put("sameRegion", new ArrayList<>());
+ RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, "TEST");
+
+ addressManager1.refreshEndpoint(event, "KIE");
+ Assertions.assertEquals("https://127.0.0.2:30103", addressManager1.address());
+ Assertions.assertEquals("http://127.0.0.1:30103", addressManager1.address());
+ Assertions.assertEquals("https://127.0.0.2:30103", addressManager1.address());
+
+ addressManager2.refreshEndpoint(event, "TEST");
+ Assertions.assertEquals("http://127.0.0.1:30100", addressManager2.address());
+ Assertions.assertEquals("http://127.0.0.1:30100", addressManager2.address());
+ }
+
+ @Test
+ public void normalizeIPV4Test() {
+ String uri = addressManager1.normalizeUri("rest://127.0.0.1:30100?sslEnabled=true");
+ Assertions.assertEquals("https://127.0.0.1:30100", uri);
+
+ uri = addressManager1.normalizeUri("rest://127.0.0.1:30100?sslEnabled=false");
+ Assertions.assertEquals("http://127.0.0.1:30100", uri);
+
+ uri = addressManager1.normalizeUri("rest://127.0.0.1:30100");
+ Assertions.assertEquals("http://127.0.0.1:30100", uri);
+ }
+
+ @Test
+ public void normalizeIPV6Test() {
+ String uri = addressManager1.normalizeUri("rest://[2008::7:957f:b2d6:1af4:a1f8]:30100?sslEnabled=true");
+ Assertions.assertEquals("https://[2008::7:957f:b2d6:1af4:a1f8]:30100", uri);
+
+ uri = addressManager1.normalizeUri("rest://[2008::7:957f:b2d6:1af4:a1f8]:30100");
+ Assertions.assertEquals("http://[2008::7:957f:b2d6:1af4:a1f8]:30100", uri);
+ }
+
+ @Test
+ public void compareAndGetAddressTest() {
+ List testAddr = new ArrayList<>();
+ testAddr.add("https://192.168.20.160:30100");
+ testAddr.add("https://127.0.0.1:30100");
+ testAddr.add("https://127.0.0.3:30100");
+ AbstractAddressManager manager = new AbstractAddressManager(testAddr, "", "");
+ Assertions.assertTrue(manager.compareAndGetAddress("192.168.20.16").isEmpty());
+ Assertions.assertEquals("https://192.168.20.160:30100", manager.compareAndGetAddress("192.168.20.160"));
+ }
+
+ @Test
+ public void AddressAffinityTest() {
+ List testAddr = new ArrayList<>();
+ testAddr.add("https://192.168.20.160:30100?region=region1&availableZone=zone1");
+ testAddr.add("https://127.0.0.1:30100");
+ AbstractAddressManager manager = new AbstractAddressManager(testAddr, "region1", "zone1");
+ Assertions.assertEquals("https://192.168.20.160:30100", manager.address());
+
+ AbstractAddressManager manager2 = new AbstractAddressManager("default", testAddr, "region1", "zone1");
+ Assertions.assertEquals("https://192.168.20.160:30100", manager2.address());
+ }
+}
diff --git a/clients/http-client-common/src/test/java/org/apache/servicecomb/http/client/common/HttpTransportImplTest.java b/clients/http-client-common/src/test/java/org/apache/servicecomb/http/client/common/HttpTransportImplTest.java
index 15095745fae..2530b80145a 100644
--- a/clients/http-client-common/src/test/java/org/apache/servicecomb/http/client/common/HttpTransportImplTest.java
+++ b/clients/http-client-common/src/test/java/org/apache/servicecomb/http/client/common/HttpTransportImplTest.java
@@ -30,8 +30,8 @@
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.servicecomb.http.client.auth.RequestAuthHeaderProvider;
-import org.junit.Assert;
-import org.junit.Test;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
public class HttpTransportImplTest {
@@ -59,9 +59,9 @@ public void TestHttpTransport() throws IOException {
HttpRequest httpRequest = new HttpRequest("111", null, null, HttpRequest.GET);
HttpResponse actualResponse = httpTransport.get(httpRequest);
- Assert.assertNotNull(actualResponse);
- Assert.assertEquals(200, actualResponse.getStatusCode());
- Assert.assertEquals("OK", actualResponse.getMessage());
- Assert.assertEquals("Test", actualResponse.getContent());
+ Assertions.assertNotNull(actualResponse);
+ Assertions.assertEquals(200, actualResponse.getStatusCode());
+ Assertions.assertEquals("OK", actualResponse.getMessage());
+ Assertions.assertEquals("Test", actualResponse.getContent());
}
}
diff --git a/clients/pom.xml b/clients/pom.xml
index e5c4626ad53..49f481934cc 100644
--- a/clients/pom.xml
+++ b/clients/pom.xml
@@ -23,7 +23,7 @@
org.apache.servicecombjava-chassis-parent
- 2.6.0-SNAPSHOT
+ 3.4.0-SNAPSHOT../parents/default4.0.0
@@ -37,6 +37,7 @@
config-commonconfig-kie-clientconfig-center-client
+ dashboard-client
diff --git a/clients/service-center-client/README.md b/clients/service-center-client/README.md
index efa5e388a4a..a6b4c6d4936 100644
--- a/clients/service-center-client/README.md
+++ b/clients/service-center-client/README.md
@@ -1,15 +1,15 @@
## ServiceComb-Service-Center Client for Java
- Sample Java client for ServiceComb-Service-Center HTTP API.
- If you want more information about the ServiceComb-Service-Center HTTP API, go [here](https://github.com/apache/servicecomb-service-center/blob/master/server/core/swagger/v4.yaml).
-
+ Sample Java client for ServiceComb-Service-Center HTTP API.
+ If you want more information about the ServiceComb-Service-Center HTTP API, go [here](https://github.com/apache/servicecomb-service-center/blob/master/docs/openapi/v4.yaml).
+
### Build & Install
-
+
local Build from source :
```
maven clean install
```
-
+
add dependency to maven
```
@@ -79,14 +79,14 @@ MicroservicesResponse services = client.getMicroserviceList();
for(Microservice microservice : services.getServices())
{
for (MicroserviceInstance instance: client.getMicroserviceInstanceList(microservice.getServiceId()).getInstances())
- {
- client.sendHeartBeats(new HeartbeatsRequest(microservice.getServiceId(),instance.getInstanceId()));
+ {
+ client.sendHeartBeats(new HeartbeatsRequest(microservice.getServiceId(),instance.getInstanceId()));
}
}
```
#### Other API
-You can see client API code and tests, go [here](https://github.com/apache/servicecomb-java-chassis/blob/master/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterClient.java)
+You can see client API code and tests, go [here](https://github.com/apache/servicecomb-java-chassis/blob/master/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterClient.java)
### More development
diff --git a/clients/service-center-client/pom.xml b/clients/service-center-client/pom.xml
index ac6d6038535..ccc3900e9db 100755
--- a/clients/service-center-client/pom.xml
+++ b/clients/service-center-client/pom.xml
@@ -22,7 +22,7 @@
clientsorg.apache.servicecomb
- 2.6.0-SNAPSHOT
+ 3.4.0-SNAPSHOT4.0.0
@@ -38,15 +38,9 @@
- junit
- junit
- test
-
-
-
- org.mockito
- mockito-core
+ com.google.guava
+ failureaccesstest
-
\ No newline at end of file
+
diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/AddressManager.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/AddressManager.java
deleted file mode 100644
index df3e96c6fb6..00000000000
--- a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/AddressManager.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.servicecomb.service.center.client;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.servicecomb.http.client.common.HttpUtils;
-
-public class AddressManager {
- private final String projectName;
-
- private final List addresses;
-
- private int index = 0;
-
- public AddressManager(String projectName, List addresses) {
- this.projectName = projectName;
- this.addresses = new ArrayList<>(addresses.size());
- this.addresses.addAll(addresses);
- }
-
- private String formatAddress(String address) {
- try {
- return address + "/v4/" + HttpUtils.encodeURLParam(this.projectName);
- } catch (Exception e) {
- throw new IllegalStateException("not possible");
- }
- }
-
- public boolean sslEnabled() {
- return address().startsWith("https://");
- }
-
- public String address() {
- synchronized (this) {
- index++;
- if (index >= addresses.size()) {
- index = 0;
- }
- return addresses.get(index);
- }
- }
-
- public String formatUrl(String url, boolean absoluteUrl) {
- return absoluteUrl ? address() + url : formatAddress(address()) + url;
- }
-}
diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/DiscoveryEvents.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/DiscoveryEvents.java
index eac6880d52e..e45720f5ebb 100644
--- a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/DiscoveryEvents.java
+++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/DiscoveryEvents.java
@@ -23,11 +23,11 @@
public abstract class DiscoveryEvents {
public static class InstanceChangedEvent extends DiscoveryEvents {
- private String appName;
+ private final String appName;
- private String serviceName;
+ private final String serviceName;
- private List instances;
+ private final List instances;
public InstanceChangedEvent(String appName, String serviceName, List instances) {
this.appName = appName;
diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/RegistrationEvents.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/RegistrationEvents.java
index 0da3ad6da66..d411913dfed 100644
--- a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/RegistrationEvents.java
+++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/RegistrationEvents.java
@@ -17,38 +17,56 @@
package org.apache.servicecomb.service.center.client;
+import org.apache.servicecomb.service.center.client.model.Microservice;
+import org.apache.servicecomb.service.center.client.model.MicroserviceInstance;
+
public abstract class RegistrationEvents {
- protected boolean success;
+ protected final boolean success;
+
+ protected final Microservice microservice;
- protected RegistrationEvents(boolean success) {
+ protected RegistrationEvents(boolean success, Microservice microservice) {
this.success = success;
+ this.microservice = microservice;
}
public boolean isSuccess() {
return this.success;
}
+ public Microservice getMicroservice() {
+ return microservice;
+ }
+
public static class MicroserviceRegistrationEvent extends RegistrationEvents {
- public MicroserviceRegistrationEvent(boolean success) {
- super(success);
+ public MicroserviceRegistrationEvent(boolean success, Microservice microservice) {
+ super(success, microservice);
}
}
public static class SchemaRegistrationEvent extends RegistrationEvents {
- public SchemaRegistrationEvent(boolean success) {
- super(success);
+ public SchemaRegistrationEvent(boolean success, Microservice microservice) {
+ super(success, microservice);
}
}
public static class MicroserviceInstanceRegistrationEvent extends RegistrationEvents {
- public MicroserviceInstanceRegistrationEvent(boolean success) {
- super(success);
+ protected final MicroserviceInstance microserviceInstance;
+
+ public MicroserviceInstanceRegistrationEvent(boolean success, Microservice microservice,
+ MicroserviceInstance microserviceInstance) {
+ super(success, microservice);
+ this.microserviceInstance = microserviceInstance;
}
}
public static class HeartBeatEvent extends RegistrationEvents {
- public HeartBeatEvent(boolean success) {
- super(success);
+ protected final MicroserviceInstance microserviceInstance;
+
+ public HeartBeatEvent(boolean success, Microservice microservice,
+ MicroserviceInstance microserviceInstance) {
+ super(success, microservice);
+ this.microserviceInstance = microserviceInstance;
}
}
}
diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterAddressManager.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterAddressManager.java
new file mode 100644
index 00000000000..b19db919e81
--- /dev/null
+++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterAddressManager.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.service.center.client;
+
+import java.util.List;
+
+import org.apache.servicecomb.http.client.common.AbstractAddressManager;
+import org.apache.servicecomb.http.client.event.RefreshEndpointEvent;
+
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+
+public class ServiceCenterAddressManager extends AbstractAddressManager {
+ public ServiceCenterAddressManager(String projectName, List addresses, EventBus eventBus, String region,
+ String availableZone) {
+ super(projectName, addresses, region, availableZone);
+ eventBus.register(this);
+ }
+
+ @Override
+ protected List transformAddress(List addresses) {
+ return addresses;
+ }
+
+ @Override
+ protected String getUrlPrefix(String address) {
+ return address + V4_PREFIX;
+ }
+
+ @Subscribe
+ public void onRefreshEndpointEvent(RefreshEndpointEvent event) {
+ refreshEndpoint(event, RefreshEndpointEvent.SERVICE_CENTER_NAME);
+ }
+}
diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterClient.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterClient.java
index 4dca259d348..97aeaa9931a 100755
--- a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterClient.java
+++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterClient.java
@@ -25,6 +25,7 @@
import java.util.Map;
import org.apache.http.HttpStatus;
+import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.utils.URIBuilder;
import org.apache.servicecomb.http.client.auth.RequestAuthHeaderProvider;
import org.apache.servicecomb.http.client.common.HttpConfiguration.SSLProperties;
@@ -32,13 +33,13 @@
import org.apache.servicecomb.http.client.common.HttpTransport;
import org.apache.servicecomb.http.client.common.HttpTransportFactory;
import org.apache.servicecomb.http.client.common.HttpUtils;
-import org.apache.servicecomb.service.center.client.OperationEvents.UnAuthorizedOperationEvent;
import org.apache.servicecomb.service.center.client.exception.OperationException;
import org.apache.servicecomb.service.center.client.model.CreateMicroserviceInstanceRequest;
import org.apache.servicecomb.service.center.client.model.CreateMicroserviceRequest;
import org.apache.servicecomb.service.center.client.model.CreateSchemaRequest;
import org.apache.servicecomb.service.center.client.model.ErrorMessage;
import org.apache.servicecomb.service.center.client.model.FindMicroserviceInstancesResponse;
+import org.apache.servicecomb.service.center.client.model.Framework;
import org.apache.servicecomb.service.center.client.model.GetSchemaListResponse;
import org.apache.servicecomb.service.center.client.model.GetSchemaResponse;
import org.apache.servicecomb.service.center.client.model.HeartbeatsRequest;
@@ -55,8 +56,10 @@
import org.apache.servicecomb.service.center.client.model.RegisteredMicroserviceInstanceResponse;
import org.apache.servicecomb.service.center.client.model.RegisteredMicroserviceResponse;
import org.apache.servicecomb.service.center.client.model.SchemaInfo;
+import org.apache.servicecomb.service.center.client.model.UpdatePropertiesRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.core.env.Environment;
import com.google.common.eventbus.EventBus;
@@ -64,31 +67,53 @@ public class ServiceCenterClient implements ServiceCenterOperation {
private static final Logger LOGGER = LoggerFactory.getLogger(ServiceCenterClient.class);
- private ServiceCenterRawClient httpClient;
+ private static final String CLIENT_CONNECT_TIMEOUT = "servicecomb.registry.sc.client.timeout.connect";
- private EventBus eventBus;
+ private static final String CLIENT_REQUEST_TIMEOUT = "servicecomb.registry.sc.client.timeout.request";
- public ServiceCenterClient(ServiceCenterRawClient httpClient) {
+ private static final String CLIENT_SOCKET_TIMEOUT = "servicecomb.registry.sc.client.timeout.socket";
+
+ private final ServiceCenterRawClient httpClient;
+
+ private final ServiceCenterAddressManager addressManager;
+
+ public ServiceCenterClient(ServiceCenterRawClient httpClient, ServiceCenterAddressManager addressManager) {
this.httpClient = httpClient;
+ this.addressManager = addressManager;
}
public ServiceCenterClient setEventBus(EventBus eventBus) {
- this.eventBus = eventBus;
+ addressManager.setEventBus(eventBus);
+ this.httpClient.setEventBus(eventBus);
return this;
}
- public ServiceCenterClient(AddressManager addressManager,
+ public ServiceCenterClient(ServiceCenterAddressManager addressManager,
SSLProperties sslProperties,
RequestAuthHeaderProvider requestAuthHeaderProvider,
String tenantName,
- Map extraGlobalHeaders) {
- HttpTransport httpTransport = HttpTransportFactory.createHttpTransport(sslProperties, requestAuthHeaderProvider);
+ Map extraGlobalHeaders,
+ Environment environment) {
+ HttpTransport httpTransport = HttpTransportFactory.createHttpTransport(sslProperties, requestAuthHeaderProvider,
+ buildRequestConfig(environment));
httpTransport.addHeaders(extraGlobalHeaders);
this.httpClient = new ServiceCenterRawClient.Builder()
.setTenantName(tenantName)
.setAddressManager(addressManager)
.setHttpTransport(httpTransport).build();
+ this.addressManager = addressManager;
+ }
+
+ private RequestConfig buildRequestConfig(Environment environment) {
+ RequestConfig.Builder builder = HttpTransportFactory.defaultRequestConfig();
+ if (environment == null) {
+ return builder.build();
+ }
+ builder.setConnectTimeout(environment.getProperty(CLIENT_CONNECT_TIMEOUT, int.class, 5000));
+ builder.setConnectionRequestTimeout(environment.getProperty(CLIENT_REQUEST_TIMEOUT, int.class, 5000));
+ builder.setSocketTimeout(environment.getProperty(CLIENT_SOCKET_TIMEOUT, int.class, 5000));
+ return builder.build();
}
@Override
@@ -98,7 +123,6 @@ public MicroserviceInstancesResponse getServiceCenterInstances() {
if (response.getStatusCode() == HttpStatus.SC_OK) {
return HttpUtils.deserialize(response.getContent(), MicroserviceInstancesResponse.class);
}
- sendUnAuthorizedEvent(response);
throw new OperationException(
"get service-center instances fails, statusCode = " + response.getStatusCode() + "; message = " + response
.getMessage()
@@ -119,7 +143,6 @@ public RegisteredMicroserviceResponse registerMicroservice(Microservice microser
if (response.getStatusCode() == HttpStatus.SC_OK) {
return HttpUtils.deserialize(response.getContent(), RegisteredMicroserviceResponse.class);
}
- sendUnAuthorizedEvent(response);
throw new OperationException(
"register service fails, statusCode = " + response.getStatusCode() + "; message = " + response
.getMessage()
@@ -137,7 +160,6 @@ public MicroservicesResponse getMicroserviceList() {
if (response.getStatusCode() == HttpStatus.SC_OK) {
return HttpUtils.deserialize(response.getContent(), MicroservicesResponse.class);
}
- sendUnAuthorizedEvent(response);
throw new OperationException(
"get service List fails, statusCode = " + response.getStatusCode() + "; message = " + response
.getMessage()
@@ -162,7 +184,6 @@ public RegisteredMicroserviceResponse queryServiceId(Microservice microservice)
if (response.getStatusCode() == HttpStatus.SC_OK) {
return HttpUtils.deserialize(response.getContent(), RegisteredMicroserviceResponse.class);
}
- sendUnAuthorizedEvent(response);
LOGGER.info("Query serviceId fails, statusCode = " + response.getStatusCode() + "; message = " + response
.getMessage()
+ "; content = " + response.getContent());
@@ -185,7 +206,6 @@ public Microservice getMicroserviceByServiceId(String serviceId) {
.deserialize(response.getContent(), MicroserviceResponse.class);
return microserviceResponse.getService();
}
- sendUnAuthorizedEvent(response);
throw new OperationException(
"get service message fails, statusCode = " + response.getStatusCode() + "; message = " + response
.getMessage()
@@ -207,7 +227,6 @@ public RegisteredMicroserviceInstanceResponse registerMicroserviceInstance(Micro
if (response.getStatusCode() == HttpStatus.SC_OK) {
return HttpUtils.deserialize(response.getContent(), RegisteredMicroserviceInstanceResponse.class);
}
- sendUnAuthorizedEvent(response);
throw new OperationException(
"register service instance fails, statusCode = " + response.getStatusCode() + "; message = " + response
.getMessage()
@@ -243,7 +262,11 @@ public FindMicroserviceInstancesResponse findMicroserviceInstance(String consume
result.setModified(false);
return result;
}
- sendUnAuthorizedEvent(response);
+ if (response.getStatusCode() == HttpStatus.SC_TOO_MANY_REQUESTS) {
+ LOGGER.warn("rate limited, keep the local service {}#{} instance cache unchanged.", appId, serviceName);
+ result.setModified(false);
+ return result;
+ }
throw new OperationException(
"get service instances list fails, statusCode = " + response.getStatusCode() + "; message = " + response
.getMessage()
@@ -262,7 +285,6 @@ public MicroserviceInstancesResponse getMicroserviceInstanceList(String serviceI
if (response.getStatusCode() == HttpStatus.SC_OK) {
return HttpUtils.deserialize(response.getContent(), MicroserviceInstancesResponse.class);
}
- sendUnAuthorizedEvent(response);
throw new OperationException(
"get service instances list fails, statusCode = " + response.getStatusCode() + "; message = " + response
.getMessage()
@@ -283,7 +305,6 @@ public MicroserviceInstance getMicroserviceInstance(String serviceId, String ins
.deserialize(response.getContent(), MicroserviceInstanceResponse.class);
return instanceResponse.getInstance();
}
- sendUnAuthorizedEvent(response);
throw new OperationException(
"get service instance message fails, statusCode = " + response.getStatusCode() + "; message = " + response
.getMessage()
@@ -303,7 +324,6 @@ public void deleteMicroserviceInstance(String serviceId, String instanceId) {
LOGGER.info("Delete service instance successfully.");
return;
}
- sendUnAuthorizedEvent(response);
throw new OperationException(
"delete service instance fails, statusCode = " + response.getStatusCode() + "; message = " + response
.getMessage()
@@ -323,7 +343,6 @@ public boolean updateMicroserviceInstanceStatus(String serviceId, String instanc
if (response.getStatusCode() == HttpStatus.SC_OK) {
return true;
}
- sendUnAuthorizedEvent(response);
throw new OperationException(
"update service instance status fails, statusCode = " + response.getStatusCode() + "; message = " + response
.getMessage()
@@ -342,7 +361,6 @@ public void sendHeartBeats(HeartbeatsRequest heartbeatsRequest) {
if (response.getStatusCode() == HttpStatus.SC_OK) {
return;
}
- sendUnAuthorizedEvent(response);
throw new OperationException(
"heartbeats fails, statusCode = " + response.getStatusCode() + "; message = " + response.getMessage()
+ "; content = " + response.getContent());
@@ -362,7 +380,6 @@ public boolean sendHeartBeat(String serviceId, String instanceId) {
if (response.getStatusCode() == HttpStatus.SC_OK) {
return true;
}
- sendUnAuthorizedEvent(response);
throw new OperationException(
"heartbeats fails, statusCode = " + response.getStatusCode() + "; message = " + response.getMessage()
+ "; content = " + response.getContent());
@@ -387,7 +404,6 @@ public List getServiceSchemasList(String serviceId, boolean withCont
.deserialize(response.getContent(), GetSchemaListResponse.class);
return getSchemaResponse.getSchemas();
}
- sendUnAuthorizedEvent(response);
throw new OperationException(
"get service schemas list fails, statusCode = " + response.getStatusCode() + "; message = " + response
.getMessage()
@@ -414,7 +430,6 @@ public String getServiceSchemaContext(String serviceId, String schemaId) {
GetSchemaResponse getSchemaResponse = HttpUtils.deserialize(response.getContent(), GetSchemaResponse.class);
return getSchemaResponse.getSchema();
}
- sendUnAuthorizedEvent(response);
throw new OperationException(
"get service schema context fails, statusCode = " + response.getStatusCode() + "; message = " + response
.getMessage()
@@ -434,7 +449,6 @@ public boolean registerSchema(String serviceId, String schemaId, CreateSchemaReq
if (response.getStatusCode() == HttpStatus.SC_OK) {
return true;
}
- sendUnAuthorizedEvent(response);
throw new OperationException(
"update service schema fails, statusCode = " + response.getStatusCode() + "; message = " + response
.getMessage()
@@ -457,7 +471,6 @@ public boolean updateServiceSchemaContext(String serviceId, SchemaInfo schemaInf
if (response.getStatusCode() == HttpStatus.SC_OK) {
return true;
}
- sendUnAuthorizedEvent(response);
throw new OperationException(
"update service schema fails, statusCode = " + response.getStatusCode() + "; message = " + response
.getMessage()
@@ -477,7 +490,6 @@ public boolean batchUpdateServiceSchemaContext(String serviceId, ModifySchemasRe
if (response.getStatusCode() == HttpStatus.SC_OK) {
return true;
}
- sendUnAuthorizedEvent(response);
throw new OperationException(
"update service schema fails, statusCode = " + response.getStatusCode() + "; message = " + response
.getMessage()
@@ -488,18 +500,12 @@ public boolean batchUpdateServiceSchemaContext(String serviceId, ModifySchemasRe
}
}
- private void sendUnAuthorizedEvent(HttpResponse response) {
- if (this.eventBus != null && response.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
- this.eventBus.post(new UnAuthorizedOperationEvent());
- }
- }
-
@Override
- public RbacTokenResponse queryToken(RbacTokenRequest request) {
+ public RbacTokenResponse queryToken(RbacTokenRequest request, String host) {
try {
+ String queryAddress = addressManager.compareAndGetAddress(host);
HttpResponse response = httpClient
- .postHttpRequestAbsoluteUrl("/v4/token", null,
- HttpUtils.serialize(request));
+ .postHttpRequestAbsoluteUrl("/v4/token", null, HttpUtils.serialize(request), queryAddress);
if (response.getStatusCode() == HttpStatus.SC_OK) {
RbacTokenResponse result = HttpUtils.deserialize(response.getContent(), RbacTokenResponse.class);
result.setStatusCode(HttpStatus.SC_OK);
@@ -527,4 +533,37 @@ public RbacTokenResponse queryToken(RbacTokenRequest request) {
"query token failed", e);
}
}
+
+ @Override
+ public boolean updateMicroserviceProperties(String serviceId, Map serviceProperties,
+ Framework framework) {
+ try {
+ UpdatePropertiesRequest request = new UpdatePropertiesRequest();
+ request.setProperties(serviceProperties);
+ request.setFramework(framework);
+ HttpResponse response = httpClient.putHttpRequest(
+ "/registry/microservices/" + serviceId + "/properties", null, HttpUtils.serialize(request));
+ if (response.getStatusCode() == HttpStatus.SC_OK) {
+ return true;
+ }
+ throw new OperationException(
+ "update service properties fails, statusCode = " + response.getStatusCode() + "; message = " + response
+ .getMessage()
+ + "; content = " + response.getContent());
+ } catch (IOException e) {
+ throw new OperationException(
+ "update service properties fails", e);
+ }
+ }
+
+ @Override
+ public void checkIsolationAddressAvailable() {
+ List isolationAddresses = addressManager.getIsolationAddresses();
+ if (isolationAddresses.isEmpty()) {
+ return;
+ }
+ for (String address : isolationAddresses) {
+ httpClient.checkAddressAvailable(address);
+ }
+ }
}
diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterDiscovery.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterDiscovery.java
index 43a9f9a5387..a1ab524c187 100644
--- a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterDiscovery.java
+++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterDiscovery.java
@@ -22,6 +22,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.servicecomb.http.client.task.AbstractTask;
@@ -45,6 +46,8 @@ public class ServiceCenterDiscovery extends AbstractTask {
private static final String ALL_VERSION = "0+";
+ private static volatile boolean pullInstanceTaskOnceInProgress = false;
+
public static class SubscriptionKey {
final String appId;
@@ -80,7 +83,7 @@ public static class SubscriptionValue {
List instancesCache;
}
- private static final Logger LOGGER = LoggerFactory.getLogger(ServiceCenterRegistration.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(ServiceCenterDiscovery.class);
private final ServiceCenterClient serviceCenterClient;
@@ -90,8 +93,6 @@ public static class SubscriptionValue {
private final Map instancesCache = new ConcurrentHashMap<>();
- private List failedInstances = new ArrayList<>();
-
private final Map microserviceCache = new ConcurrentHashMap<>();
private long pollInterval = 15000;
@@ -100,6 +101,8 @@ public static class SubscriptionValue {
private final Object lock = new Object();
+ private final Random random = new Random();
+
public ServiceCenterDiscovery(ServiceCenterClient serviceCenterClient, EventBus eventBus) {
super("service-center-discovery-task");
this.serviceCenterClient = serviceCenterClient;
@@ -131,7 +134,7 @@ public void registerIfNotPresent(SubscriptionKey subscriptionKey) {
synchronized (lock) {
if (this.instancesCache.get(subscriptionKey) == null) {
SubscriptionValue value = new SubscriptionValue();
- pullInstance(subscriptionKey, value);
+ pullInstance(subscriptionKey, value, false);
this.instancesCache.put(subscriptionKey, value);
}
}
@@ -144,14 +147,20 @@ public List getInstanceCache(SubscriptionKey key) {
@Subscribe
public void onPullInstanceEvent(PullInstanceEvent event) {
- pullAllInstance();
+ // to avoid too many pulls queued.
+ if (pullInstanceTaskOnceInProgress) {
+ return;
+ }
+ pullInstanceTaskOnceInProgress = true;
+ startTask(new PullInstanceOnceTask());
}
- private void pullInstance(SubscriptionKey k, SubscriptionValue v) {
+ private void pullInstance(SubscriptionKey k, SubscriptionValue v, boolean sendChangedEvent) {
if (myselfServiceId == null) {
// registration not ready
return;
}
+
try {
FindMicroserviceInstancesResponse instancesResponse = serviceCenterClient
.findMicroserviceInstance(myselfServiceId, k.appId, k.serviceName, ALL_VERSION, v.revision);
@@ -159,10 +168,10 @@ private void pullInstance(SubscriptionKey k, SubscriptionValue v) {
List instances = instancesResponse.getMicroserviceInstancesResponse().getInstances()
== null ? Collections.emptyList() : instancesResponse.getMicroserviceInstancesResponse().getInstances();
setMicroserviceInfo(instances);
- LOGGER.info("Instance changed event, "
- + "current: revision={}, instances={}; "
- + "origin: revision={}, instances={}; "
- + "appId={}, serviceName={}",
+ LOGGER.info("Instance changed event. "
+ + "Current: revision={}, instances={}. "
+ + "Origin: revision={}, instances={}. "
+ + "appId={}, serviceName={}.",
instancesResponse.getRevision(),
instanceToString(instances),
v.revision,
@@ -172,12 +181,14 @@ private void pullInstance(SubscriptionKey k, SubscriptionValue v) {
);
v.instancesCache = instances;
v.revision = instancesResponse.getRevision();
- eventBus.post(new InstanceChangedEvent(k.appId, k.serviceName,
- v.instancesCache));
+ if (sendChangedEvent) {
+ eventBus.post(new InstanceChangedEvent(k.appId, k.serviceName,
+ v.instancesCache));
+ }
}
} catch (Exception e) {
- LOGGER.error("find service {}#{} instance failed.", k.appId, k.serviceName, e);
- failedInstances.add(k);
+ LOGGER.warn("find service {}#{} instance failed, remaining local instances cache [{}], cause message: {}",
+ k.appId, k.serviceName, instanceToString(v.instancesCache), e.getMessage());
}
}
@@ -201,19 +212,38 @@ class PullInstanceTask implements Task {
public void execute() {
pullAllInstance();
- startTask(new BackOffSleepTask(pollInterval, new PullInstanceTask()));
+ startTask(new BackOffSleepTask(buildPollIntervalWithSalt(), new PullInstanceTask()));
+ }
+ }
+
+ private long buildPollIntervalWithSalt() {
+ int positive = random.nextInt(5);
+ int sign = random.nextBoolean() ? 1 : -1;
+ long currentPollInterval = pollInterval + sign * positive * 1000;
+ return currentPollInterval > 0 ? currentPollInterval : pollInterval;
+ }
+
+ class PullInstanceOnceTask implements Task {
+ @Override
+ public void execute() {
+ try {
+ pullAllInstance();
+ } finally {
+ pullInstanceTaskOnceInProgress = false;
+ }
}
}
private synchronized void pullAllInstance() {
+ List emptyInstancesCache = new ArrayList<>();
instancesCache.forEach((k, v) -> {
- pullInstance(k, v);
+ pullInstance(k, v, true);
+ if (v.instancesCache.isEmpty()) {
+ emptyInstancesCache.add(k);
+ }
});
- if (failedInstances.isEmpty()) {
- return;
- }
- failedInstances.forEach(item -> instancesCache.remove(item));
- failedInstances.clear();
+ emptyInstancesCache.forEach(instancesCache::remove);
+ emptyInstancesCache.clear();
}
private static String instanceToString(List instances) {
@@ -227,10 +257,9 @@ private static String instanceToString(List instances) {
sb.append(endpoint.length() > 64 ? endpoint.substring(0, 64) : endpoint);
sb.append("|");
}
- sb.append(instance.getServiceName());
+ sb.append(instance.getStatus());
sb.append("|");
}
- sb.append("#");
return sb.toString();
}
}
diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterOperation.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterOperation.java
index 9c28ac36a8d..fd39a4ce963 100644
--- a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterOperation.java
+++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterOperation.java
@@ -18,10 +18,12 @@
package org.apache.servicecomb.service.center.client;
import java.util.List;
+import java.util.Map;
import org.apache.servicecomb.service.center.client.exception.OperationException;
import org.apache.servicecomb.service.center.client.model.CreateSchemaRequest;
import org.apache.servicecomb.service.center.client.model.FindMicroserviceInstancesResponse;
+import org.apache.servicecomb.service.center.client.model.Framework;
import org.apache.servicecomb.service.center.client.model.HeartbeatsRequest;
import org.apache.servicecomb.service.center.client.model.Microservice;
import org.apache.servicecomb.service.center.client.model.MicroserviceInstance;
@@ -158,7 +160,6 @@ boolean updateMicroserviceInstanceStatus(String serviceId, String instanceId,
* Batch send heartbeats to service-center
*
* @param heartbeatsRequest
- * @return
* @throws OperationException
*/
void sendHeartBeats(HeartbeatsRequest heartbeatsRequest);
@@ -183,5 +184,19 @@ boolean updateMicroserviceInstanceStatus(String serviceId, String instanceId,
* @return if heartbeat is successful
* @throws OperationException If some problems happened to contact service center or non http 200 returned.
*/
- RbacTokenResponse queryToken(RbacTokenRequest request);
+ RbacTokenResponse queryToken(RbacTokenRequest request, String host);
+
+ /**
+ * Update properties of microservice
+ *
+ * @return if update is successful
+ * @throws OperationException If some problems happened to contact service center or non http 200 returned.
+ */
+ boolean updateMicroserviceProperties(String microserviceId, Map serviceProperties,
+ Framework framework);
+
+ /**
+ * Check serviceCenter isolation address available
+ */
+ void checkIsolationAddressAvailable();
}
diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterRawClient.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterRawClient.java
index 3b9a48bfe1b..e233f15fb52 100755
--- a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterRawClient.java
+++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterRawClient.java
@@ -21,84 +21,121 @@
import java.util.HashMap;
import java.util.Map;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.HttpStatus;
import org.apache.servicecomb.http.client.common.HttpRequest;
import org.apache.servicecomb.http.client.common.HttpResponse;
import org.apache.servicecomb.http.client.common.HttpTransport;
+import org.apache.servicecomb.http.client.event.OperationEvents.UnAuthorizedOperationEvent;
+import org.apache.servicecomb.http.client.utils.ServiceCombServiceAvailableUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.eventbus.EventBus;
+
public class ServiceCenterRawClient {
private static final Logger LOGGER = LoggerFactory.getLogger(ServiceCenterRawClient.class);
private static final String HEADER_TENANT_NAME = "x-domain-name";
- private String tenantName;
+ private static final String ADDRESS_CHECK_PATH = "/v4/default/registry/health/readiness";
+
+ private final String tenantName;
+
+ private final HttpTransport httpTransport;
- private HttpTransport httpTransport;
+ private final ServiceCenterAddressManager addressManager;
- private AddressManager addressManager;
+ private EventBus eventBus;
private ServiceCenterRawClient(String tenantName, HttpTransport httpTransport,
- AddressManager addressManager) {
+ ServiceCenterAddressManager addressManager) {
this.httpTransport = httpTransport;
this.tenantName = tenantName;
this.addressManager = addressManager;
}
+ public void setEventBus(EventBus eventBus) {
+ this.eventBus = eventBus;
+ }
+
public HttpResponse getHttpRequest(String url, Map headers, String content) throws IOException {
- return doHttpRequest(url, false, headers, content, HttpRequest.GET);
+ return doHttpRequest(url, false, headers, content, HttpRequest.GET, "");
}
- public HttpResponse postHttpRequestAbsoluteUrl(String url, Map headers, String content)
- throws IOException {
- return doHttpRequest(url, true, headers, content, HttpRequest.POST);
+ public HttpResponse postHttpRequestAbsoluteUrl(String url, Map headers, String content,
+ String address) throws IOException {
+ return doHttpRequest(url, true, headers, content, HttpRequest.POST, address);
}
public HttpResponse postHttpRequest(String url, Map headers, String content) throws IOException {
- return doHttpRequest(url, false, headers, content, HttpRequest.POST);
+ return doHttpRequest(url, false, headers, content, HttpRequest.POST, "");
}
public HttpResponse putHttpRequest(String url, Map headers, String content) throws IOException {
- return doHttpRequest(url, false, headers, content, HttpRequest.PUT);
+ return doHttpRequest(url, false, headers, content, HttpRequest.PUT, "");
}
public HttpResponse deleteHttpRequest(String url, Map headers, String content) throws IOException {
- return doHttpRequest(url, false, headers, content, HttpRequest.DELETE);
+ return doHttpRequest(url, false, headers, content, HttpRequest.DELETE, "");
}
private HttpResponse doHttpRequest(String url, boolean absoluteUrl, Map headers, String content,
- String method)
- throws IOException {
-
- String address = addressManager.formatUrl(url, absoluteUrl);
- if (headers == null) {
- headers = new HashMap<>();
- }
- headers.put(HEADER_TENANT_NAME, tenantName);
- HttpRequest httpRequest = new HttpRequest(address, headers, content, method);
-
+ String method, String queryAddress) throws IOException {
+ String address = StringUtils.isEmpty(queryAddress) ? addressManager.address() : queryAddress;
+ String formatUrl = addressManager.formatUrl(url, absoluteUrl, address);
+ HttpRequest httpRequest = buildHttpRequest(formatUrl, headers, content, method);
+ HttpResponse httpResponse;
try {
- return httpTransport.doRequest(httpRequest);
+ httpResponse = httpTransport.doRequest(httpRequest);
+ recordAndSendUnAuthorizedEvent(httpResponse, address);
+ return httpResponse;
} catch (IOException e) {
- String retryAddress = addressManager.formatUrl(url, absoluteUrl);
- LOGGER.warn("send request to {} failed and retry to {} once. ", address,
- retryAddress, e);
- httpRequest = new HttpRequest(retryAddress, headers, content, method);
+ addressManager.recordFailState(address);
+ String retryAddress = addressManager.address();
+ formatUrl = addressManager.formatUrl(url, absoluteUrl, retryAddress);
+ LOGGER.warn("send request to {} failed and retry to {} once. ", address, retryAddress, e);
+ httpRequest = new HttpRequest(formatUrl, headers, content, method);
try {
- return httpTransport.doRequest(httpRequest);
+ httpResponse = httpTransport.doRequest(httpRequest);
+ recordAndSendUnAuthorizedEvent(httpResponse, retryAddress);
+ return httpResponse;
} catch (IOException ioException) {
+ addressManager.recordFailState(retryAddress);
LOGGER.warn("retry to {} failed again. ", retryAddress, e);
throw ioException;
}
}
}
+ private void recordAndSendUnAuthorizedEvent(HttpResponse response, String address) {
+ if (this.eventBus != null && response.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
+ LOGGER.warn("request unauthorized from server [{}], message [{}]", address, response.getMessage());
+ addressManager.recordFailState(address);
+ this.eventBus.post(new UnAuthorizedOperationEvent(address));
+ } else {
+ addressManager.recordSuccessState(address);
+ }
+ }
+
+ public void checkAddressAvailable(String address) {
+ ServiceCombServiceAvailableUtils.checkAddressAvailable(addressManager, address, httpTransport, ADDRESS_CHECK_PATH);
+ }
+
+ private HttpRequest buildHttpRequest(String url, Map headers, String content, String method) {
+ if (headers == null) {
+ headers = new HashMap<>();
+ }
+ headers.put(HEADER_TENANT_NAME, tenantName);
+ return new HttpRequest(url, headers, content, method);
+ }
+
public static class Builder {
private String tenantName;
private HttpTransport httpTransport;
- private AddressManager addressManager;
+ private ServiceCenterAddressManager addressManager;
public Builder() {
}
@@ -113,7 +150,7 @@ public Builder setHttpTransport(HttpTransport httpTransport) {
return this;
}
- public Builder setAddressManager(AddressManager addressManager) {
+ public Builder setAddressManager(ServiceCenterAddressManager addressManager) {
this.addressManager = addressManager;
return this;
}
diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterRegistration.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterRegistration.java
index 0786feb7c79..93988ea8948 100644
--- a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterRegistration.java
+++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterRegistration.java
@@ -17,7 +17,9 @@
package org.apache.servicecomb.service.center.client;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.servicecomb.http.client.task.AbstractTask;
@@ -54,9 +56,9 @@ public class ServiceCenterRegistration extends AbstractTask {
private MicroserviceInstance microserviceInstance;
- private List schemaInfos;
+ private List schemaInfos = new ArrayList<>();
- private ServiceCenterConfiguration serviceCenterConfiguration;
+ private final ServiceCenterConfiguration serviceCenterConfiguration;
private long heartBeatInterval = 15000;
@@ -101,8 +103,18 @@ public ServiceCenterRegistration setSchemaInfos(List schemaInfos) {
return this;
}
+ public ServiceCenterRegistration addSchemaInfo(SchemaInfo schemaInfo) {
+ this.schemaInfos.add(schemaInfo);
+ return this;
+ }
+
+ public List getSchemaInfos() {
+ return this.schemaInfos;
+ }
+
public void startRegistration() {
startTask(new RegisterMicroserviceTask(0));
+ schedulerCheckAddressAvailable("sc-addr-check", new CheckAddressTask(), heartBeatInterval);
}
class RegisterMicroserviceTask implements Task {
@@ -120,46 +132,64 @@ public void execute() {
RegisteredMicroserviceResponse response = serviceCenterClient.registerMicroservice(microservice);
if (StringUtils.isEmpty(response.getServiceId())) {
LOGGER.error("register microservice failed, and will try again.");
- eventBus.post(new MicroserviceRegistrationEvent(false));
+ eventBus.post(new MicroserviceRegistrationEvent(false, microservice));
startTask(new BackOffSleepTask(failedCount + 1, new RegisterMicroserviceTask(failedCount + 1)));
return;
}
microservice.setServiceId(response.getServiceId());
microserviceInstance.setServiceId(response.getServiceId());
microserviceInstance.setMicroservice(microservice);
- eventBus.post(new MicroserviceRegistrationEvent(true));
+ eventBus.post(new MicroserviceRegistrationEvent(true, microservice));
startTask(new RegisterSchemaTask(0));
} else {
Microservice newMicroservice = serviceCenterClient.getMicroserviceByServiceId(serviceResponse.getServiceId());
- dealIsSwaggerDifferent(newMicroservice);
+
+ Map propertiesTemp = microservice.getProperties();
+ microservice.setProperties(newMicroservice.getProperties());
+ microservice.getProperties().putAll(propertiesTemp);
+ if (serviceCenterClient.updateMicroserviceProperties(serviceResponse.getServiceId(),
+ microservice.getProperties(), microservice.getFramework())) {
+ LOGGER.info(
+ "microservice is already registered. Update microservice properties successfully. properties=[{}], "
+ + "frameworkVersion [{}]", microservice.getProperties(), microservice.getFramework().getVersion());
+ } else {
+ LOGGER.error("microservice is already registered. Update microservice properties failed. properties=[{}], "
+ + "frameworkVersion [{}]", microservice.getProperties(), microservice.getFramework().getVersion());
+ }
+
microservice.setServiceId(serviceResponse.getServiceId());
microserviceInstance.setServiceId(serviceResponse.getServiceId());
microserviceInstance.setMicroservice(microservice);
- eventBus.post(new MicroserviceRegistrationEvent(true));
- LOGGER.info("microservice is already registered, meta info like swagger contents will not be updated.");
+ if (isSwaggerDifferent(newMicroservice)) {
+ if (serviceCenterConfiguration.isCanOverwriteSwagger()) {
+ LOGGER.warn("Service has already registered, but schema ids not equal, try to register it again");
+ eventBus.post(new MicroserviceRegistrationEvent(true, microservice));
+ startTask(new RegisterSchemaTask(0));
+ return;
+ }
+ if (serviceCenterConfiguration.isIgnoreSwaggerDifferent()) {
+ LOGGER.warn("Service has already registered, but schema ids not equal. Ignore and continue to register");
+ } else {
+ throw new IllegalStateException(
+ "Service has already registered, but schema ids not equal, stop register. "
+ + "Change the microservice version or delete the old microservice info and try again.");
+ }
+ }
+ eventBus.post(new MicroserviceRegistrationEvent(true, microservice));
startTask(new RegisterMicroserviceInstanceTask(0));
}
} catch (IllegalStateException e) {
throw e;
} catch (Exception e) {
LOGGER.error("register microservice failed, and will try again.", e);
- eventBus.post(new MicroserviceRegistrationEvent(false));
+ eventBus.post(new MicroserviceRegistrationEvent(false, microservice));
startTask(new BackOffSleepTask(failedCount + 1, new RegisterMicroserviceTask(failedCount + 1)));
}
}
}
- private void dealIsSwaggerDifferent(Microservice newMicroservice) {
- if (isListEquals(newMicroservice.getSchemas(), microservice.getSchemas())) {
- return;
- }
- if (!serviceCenterConfiguration.isIgnoreSwaggerDifferent()) {
- throw new IllegalStateException("Service has already registered, but schema ids not equal, stop register. "
- + "Change the microservice version or delete the old microservice info and try again.");
- }
- LOGGER.warn("Service has already registered, but schema ids not equal. However, it will continue to register. "
- + "If you want to eliminate this warning. you can Change the microservice version or delete the old " +
- "microservice info and try again. eg: version:1.0.0 -> 1.0.1");
+ private boolean isSwaggerDifferent(Microservice newMicroservice) {
+ return !isListEquals(newMicroservice.getSchemas(), microservice.getSchemas());
}
private boolean isListEquals(List one, List two) {
@@ -178,7 +208,7 @@ public void execute() {
try {
if (schemaInfos == null || schemaInfos.isEmpty()) {
LOGGER.warn("no schemas defined for this microservice.");
- eventBus.post(new SchemaRegistrationEvent(true));
+ eventBus.post(new SchemaRegistrationEvent(true, microservice));
startTask(new RegisterMicroserviceInstanceTask(0));
return;
}
@@ -189,18 +219,18 @@ public void execute() {
request.setSummary(schemaInfo.getSummary());
if (!serviceCenterClient.registerSchema(microservice.getServiceId(), schemaInfo.getSchemaId(), request)) {
LOGGER.error("register schema content failed, and will try again.");
- eventBus.post(new SchemaRegistrationEvent(false));
+ eventBus.post(new SchemaRegistrationEvent(false, microservice));
// back off by multiply
startTask(new BackOffSleepTask(failedCount + 1, new RegisterSchemaTask((failedCount + 1) * 2)));
return;
}
}
- eventBus.post(new SchemaRegistrationEvent(true));
+ eventBus.post(new SchemaRegistrationEvent(true, microservice));
startTask(new RegisterMicroserviceInstanceTask(0));
} catch (Exception e) {
LOGGER.error("register schema content failed, and will try again.", e);
- eventBus.post(new SchemaRegistrationEvent(false));
+ eventBus.post(new SchemaRegistrationEvent(false, microservice));
// back off by multiply
startTask(new BackOffSleepTask(failedCount + 1, new RegisterSchemaTask((failedCount + 1) * 2)));
}
@@ -221,25 +251,25 @@ public void execute() {
.registerMicroserviceInstance(microserviceInstance);
if (instance == null) {
LOGGER.error("register microservice instance failed, and will try again.");
- eventBus.post(new MicroserviceInstanceRegistrationEvent(false));
+ eventBus.post(new MicroserviceInstanceRegistrationEvent(false, microservice, microserviceInstance));
startTask(new BackOffSleepTask(failedCount + 1, new RegisterMicroserviceInstanceTask(failedCount + 1)));
} else {
microserviceInstance.setInstanceId(instance.getInstanceId());
LOGGER.info("register microservice successfully, service id={}, instance id={}", microservice.getServiceId(),
microserviceInstance.getInstanceId());
- eventBus.post(new MicroserviceInstanceRegistrationEvent(true));
+ eventBus.post(new MicroserviceInstanceRegistrationEvent(true, microservice, microserviceInstance));
startTask(new SendHeartBeatTask(0));
}
} catch (Exception e) {
LOGGER.error("register microservice instance failed, and will try again.", e);
- eventBus.post(new MicroserviceInstanceRegistrationEvent(false));
+ eventBus.post(new MicroserviceInstanceRegistrationEvent(false, microservice, microserviceInstance));
startTask(new BackOffSleepTask(failedCount + 1, new RegisterMicroserviceInstanceTask(failedCount + 1)));
}
}
}
class SendHeartBeatTask implements Task {
- final int failedRetry = 3;
+ private static final int FAILED_RETRY = 3;
int failedCount;
@@ -250,27 +280,39 @@ class SendHeartBeatTask implements Task {
@Override
public void execute() {
try {
- if (failedCount >= failedRetry) {
- eventBus.post(new HeartBeatEvent(false));
+ if (failedCount >= FAILED_RETRY) {
+ eventBus.post(new HeartBeatEvent(false, microservice, microserviceInstance));
startTask(new RegisterMicroserviceTask(0));
return;
}
if (!serviceCenterClient.sendHeartBeat(microservice.getServiceId(), microserviceInstance.getInstanceId())) {
- LOGGER.error("send heart failed, and will try again.");
- eventBus.post(new HeartBeatEvent(false));
+ LOGGER.warn("send heart failed, and will try again.");
+ eventBus.post(new HeartBeatEvent(false, microservice, microserviceInstance));
startTask(new BackOffSleepTask(failedCount + 1, new SendHeartBeatTask(failedCount + 1)));
} else {
// wait 10 * 3000 ms and send heart beat again.
- eventBus.post(new HeartBeatEvent(true));
+ eventBus.post(new HeartBeatEvent(true, microservice, microserviceInstance));
startTask(
new BackOffSleepTask(Math.max(heartBeatInterval, heartBeatRequestTimeout), new SendHeartBeatTask(0)));
}
} catch (Exception e) {
- LOGGER.error("send heart failed, and will try again.", e);
- eventBus.post(new HeartBeatEvent(false));
+ // If heartbeat failures three times, log error stack help troubleshooting. Others just log message as warn.
+ if (failedCount == 2) {
+ LOGGER.error("send heart failed, and will try again.", e);
+ } else {
+ LOGGER.warn("send heart failed, and will try again. message [{}]", e.getMessage());
+ }
+ eventBus.post(new HeartBeatEvent(false, microservice, microserviceInstance));
startTask(new BackOffSleepTask(failedCount + 1, new SendHeartBeatTask(failedCount + 1)));
}
}
}
+
+ class CheckAddressTask implements Runnable {
+ @Override
+ public void run() {
+ serviceCenterClient.checkIsolationAddressAvailable();
+ }
+ }
}
diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterWatch.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterWatch.java
index d8faafabe1b..9f24a74a55a 100644
--- a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterWatch.java
+++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterWatch.java
@@ -17,12 +17,15 @@
package org.apache.servicecomb.service.center.client;
+import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.servicecomb.foundation.auth.SignRequest;
import org.apache.servicecomb.http.client.auth.RequestAuthHeaderProvider;
import org.apache.servicecomb.http.client.common.HttpConfiguration.SSLProperties;
import org.apache.servicecomb.http.client.common.WebSocketListener;
@@ -51,7 +54,7 @@ public class ServiceCenterWatch implements WebSocketListener {
private static final long SLEEP_MAX = 10 * 60 * 10000;
- private final AddressManager addressManager;
+ private final ServiceCenterAddressManager addressManager;
private final SSLProperties sslProperties;
@@ -67,7 +70,7 @@ public class ServiceCenterWatch implements WebSocketListener {
private String serviceId;
- private int continuousError = 0;
+ private AtomicInteger continuousError = new AtomicInteger(0);
private final AtomicBoolean reconnecting = new AtomicBoolean(false);
@@ -78,7 +81,7 @@ public class ServiceCenterWatch implements WebSocketListener {
private final ExecutorService connector = Executors.newFixedThreadPool(1, (r) -> new
Thread(r, "web-socket-connector"));
- public ServiceCenterWatch(AddressManager addressManager,
+ public ServiceCenterWatch(ServiceCenterAddressManager addressManager,
SSLProperties sslProperties,
RequestAuthHeaderProvider requestAuthHeaderProvider,
String tenantName,
@@ -102,25 +105,37 @@ public void startWatch(String project, String serviceId) {
private void startWatch() {
connector.submit(() -> {
backOff();
-
+ String address = addressManager.address();
try {
Map headers = new HashMap<>();
headers.put("x-domain-name", this.tenantName);
headers.putAll(this.extraGlobalHeaders);
- headers.putAll(this.requestAuthHeaderProvider.loadAuthHeader(null));
- currentServerUri = convertAddress();
+ headers.putAll(this.requestAuthHeaderProvider.loadAuthHeader(createSignRequest(address)));
+ currentServerUri = convertAddress(address);
LOGGER.info("start watch to address {}", currentServerUri);
webSocketTransport = new WebSocketTransport(currentServerUri, sslProperties,
headers, this);
webSocketTransport.connectBlocking();
+ addressManager.recordSuccessState(address);
} catch (Exception e) {
+ addressManager.recordFailState(address);
LOGGER.error("start watch failed. ", e);
}
});
}
- private String convertAddress() {
- String address = addressManager.address();
+ private SignRequest createSignRequest(String url) {
+ try {
+ URI uri = URI.create(url);
+ SignRequest signRequest = new SignRequest();
+ signRequest.setEndpoint(uri);
+ return signRequest;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ private String convertAddress(String address) {
String url = String.format(WATCH, project, serviceId);
if (address.startsWith(HTTP)) {
return WS + address.substring(HTTP.length()) + url;
@@ -129,7 +144,6 @@ private String convertAddress() {
if (address.startsWith(HTTPS)) {
return WSS + address.substring(HTTPS.length()) + url;
}
-
return address + url;
}
@@ -143,7 +157,7 @@ private void reconnect() {
if (reconnecting.getAndSet(true)) {
return;
}
- continuousError++;
+ continuousError.incrementAndGet();
if (webSocketTransport != null) {
webSocketTransport.close();
}
@@ -151,11 +165,11 @@ private void reconnect() {
}
private void backOff() {
- if (this.continuousError <= 0) {
+ if (this.continuousError.get() <= 0) {
return;
}
try {
- Thread.sleep(Math.min(SLEEP_MAX, this.continuousError * this.continuousError * SLEEP_BASE));
+ Thread.sleep(Math.min(SLEEP_MAX, this.continuousError.get() * this.continuousError.get() * SLEEP_BASE));
} catch (InterruptedException e) {
// do not care
}
@@ -183,7 +197,7 @@ public void onOpen(ServerHandshake serverHandshake) {
LOGGER.info("web socket connected to server {}, status={}, message={}", currentServerUri,
serverHandshake.getHttpStatus(),
serverHandshake.getHttpStatusMessage());
- continuousError = 0;
+ continuousError.set(0);
reconnecting.set(false);
}
}
diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/HeartbeatsRequest.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/HeartbeatsRequest.java
index 9235523c3b6..9f4ea115cfe 100755
--- a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/HeartbeatsRequest.java
+++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/HeartbeatsRequest.java
@@ -24,7 +24,7 @@ public class HeartbeatsRequest {
private List Instances;
public HeartbeatsRequest(String serviceId, String instanceId) {
- List instances = new ArrayList();
+ List instances = new ArrayList<>();
instances.add(new InstancesRequest(serviceId, instanceId));
this.Instances = instances;
}
@@ -41,7 +41,7 @@ public void addInstances(InstancesRequest instancesRequest) {
if (this.Instances != null) {
this.Instances.add(instancesRequest);
} else {
- this.Instances = new ArrayList();
+ this.Instances = new ArrayList<>();
this.Instances.add(instancesRequest);
}
}
diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/Microservice.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/Microservice.java
index 1c2fc88a1db..a034e57569f 100755
--- a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/Microservice.java
+++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/Microservice.java
@@ -208,4 +208,8 @@ public List getPaths() {
public void setPaths(List paths) {
this.paths = paths;
}
+
+ public void addSchema(String schema) {
+ this.schemas.add(schema);
+ }
}
diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroserviceInstance.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroserviceInstance.java
index 068501a84ba..7f03c314043 100755
--- a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroserviceInstance.java
+++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/MicroserviceInstance.java
@@ -36,13 +36,13 @@ public class MicroserviceInstance {
private String version;
- private List endpoints = new ArrayList();
+ private List endpoints = new ArrayList<>();
private String hostName;
private MicroserviceInstanceStatus status;
- private Map properties = new HashMap(); // reserved key list: region|az|stage|group
+ private Map properties = new HashMap<>(); // reserved key list: region|az|stage|group
private HealthCheck healthCheck;
@@ -147,6 +147,11 @@ public void setMicroservice(Microservice microservice) {
this.microservice = microservice;
}
+ @JsonIgnore
+ public Microservice getMicroservice() {
+ return this.microservice;
+ }
+
@JsonIgnore
public String getServiceName() {
return this.microservice.getServiceName();
@@ -156,4 +161,12 @@ public String getServiceName() {
public String getApplicationName() {
return this.microservice.getAppId();
}
+
+ public void addEndpoint(String endpoint) {
+ this.endpoints.add(endpoint);
+ }
+
+ public void addProperty(String key, String value) {
+ this.properties.put(key, value);
+ }
}
diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/SchemaInfo.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/SchemaInfo.java
index 720e0e98b0e..40180433d0b 100755
--- a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/SchemaInfo.java
+++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/SchemaInfo.java
@@ -57,4 +57,4 @@ public String getSummary() {
public void setSummary(String summary) {
this.summary = summary;
}
-}
\ No newline at end of file
+}
diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/ServiceCenterConfiguration.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/ServiceCenterConfiguration.java
index a452259809e..bc7618aa0f5 100644
--- a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/ServiceCenterConfiguration.java
+++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/ServiceCenterConfiguration.java
@@ -24,14 +24,25 @@ public class ServiceCenterConfiguration {
* when swagger is different between local with remote serviceCenter. if ignoreSwaggerDifferent is true.
* it will ignore the different and continue the program. otherwise, the program will be stop.
*/
- private Boolean ignoreSwaggerDifferent;
+ private boolean ignoreSwaggerDifferent;
- public Boolean isIgnoreSwaggerDifferent() {
+ private boolean canOverwriteSwagger = true;
+
+ public boolean isIgnoreSwaggerDifferent() {
return ignoreSwaggerDifferent;
}
- public ServiceCenterConfiguration setIgnoreSwaggerDifferent(Boolean ignoreSwaggerDifferent) {
+ public boolean isCanOverwriteSwagger(){
+ return canOverwriteSwagger;
+ }
+
+ public ServiceCenterConfiguration setIgnoreSwaggerDifferent(boolean ignoreSwaggerDifferent) {
this.ignoreSwaggerDifferent = ignoreSwaggerDifferent;
return this;
}
+
+ public ServiceCenterConfiguration setCanOverwriteSwagger(boolean canOverwriteSwagger) {
+ this.canOverwriteSwagger = canOverwriteSwagger;
+ return this;
+ }
}
diff --git a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/api/request/UpdatePropertiesRequest.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/UpdatePropertiesRequest.java
similarity index 81%
rename from service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/api/request/UpdatePropertiesRequest.java
rename to clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/UpdatePropertiesRequest.java
index 5e08a22a9b4..d7d4b093930 100644
--- a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/api/request/UpdatePropertiesRequest.java
+++ b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/model/UpdatePropertiesRequest.java
@@ -15,16 +15,15 @@
* limitations under the License.
*/
-package org.apache.servicecomb.serviceregistry.api.request;
+package org.apache.servicecomb.service.center.client.model;
import java.util.Map;
-/**
- * 更新微服务和实例properties的request
- */
public class UpdatePropertiesRequest {
private Map properties;
+ private Framework framework;
+
public Map getProperties() {
return properties;
}
@@ -32,4 +31,12 @@ public Map getProperties() {
public void setProperties(Map properties) {
this.properties = properties;
}
+
+ public Framework getFramework() {
+ return framework;
+ }
+
+ public void setFramework(Framework framework) {
+ this.framework = framework;
+ }
}
diff --git a/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterAddressManagerTest.java b/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterAddressManagerTest.java
new file mode 100644
index 00000000000..a2888cfad1b
--- /dev/null
+++ b/clients/service-center-client/src/test/java/org/apache/servicecomb/service/center/client/ServiceCenterAddressManagerTest.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.service.center.client;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.servicecomb.http.client.event.RefreshEndpointEvent;
+
+import com.google.common.eventbus.EventBus;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class ServiceCenterAddressManagerTest {
+
+ private static final List addresses = new ArrayList<>();
+
+ private static ServiceCenterAddressManager addressManager1;
+
+ private static ServiceCenterAddressManager addressManager2;
+
+
+ @Test
+ public void getUrlPrefix() {
+ addresses.add("http://127.0.0.1:30103");
+ addressManager1 = new ServiceCenterAddressManager("project", addresses, new EventBus(), "", "");
+
+ Assertions.assertNotNull(addressManager1);
+
+ List addresses = addressManager1.getAddresses();
+ Assertions.assertEquals(1, addresses.size());
+ Assertions.assertEquals("http://127.0.0.1:30103", addresses.get(0));
+ Assertions.assertEquals("http://127.0.0.1:30103", addressManager1.address());
+ Assertions.assertEquals("http://127.0.0.1:30103/v4/", addressManager1.getUrlPrefix("http://127.0.0.1:30103"));
+ }
+
+ @Test
+ public void formatUrlTest() {
+ addresses.add("http://127.0.0.1:30103");
+ addressManager1 = new ServiceCenterAddressManager("project", addresses, new EventBus(), "", "");
+ Assertions.assertNotNull(addressManager1);
+
+ String address = addressManager1.address();
+ Assertions.assertEquals("http://127.0.0.1:30103", address);
+ String url = addressManager1.formatUrl("/test/", false, address);
+ Assertions.assertEquals("http://127.0.0.1:30103/v4/project/test/", url);
+
+ url = addressManager1.formatUrl("/test/", true, address);
+ Assertions.assertEquals("http://127.0.0.1:30103/test/", url);
+ }
+
+ @Test
+ public void onRefreshEndpointEvent() {
+ List addressAZ = new ArrayList<>();
+ addressAZ.add("http://127.0.0.3:30100");
+ List