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 933e7a1b04e..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@v1
+ 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
+ ${{ 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 58d645decb8..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]: https://docs.servicecomb.io/java-chassis/en_US/
+[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 47695c4c01a..bfae9746c2b 100644
--- a/README_ZH.md
+++ b/README_ZH.md
@@ -1,68 +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等,满足不同场景对于性能、韧性的需求。
+* 统一一致的服务提供者、服务消费者处理链,易于扩展新功能。
+* 提供服务发现、配置管理、熔断、限流、灰度发布等开箱即用的服务治理能力。
-开发者可以通过[设计选型参考](https://docs.servicecomb.io/java-chassis/zh_CN/start/design/)了解更多特性和设计原理。
+可以通过[设计选型参考](https://servicecomb.apache.org/references/java-chassis/zh_CN/start/design.html) 了解更多特性和设计原理。
-# 为什么使用Java Chassis
+> 如果发现项目能帮助到您,别忘了点击右上角`star`表示鼓励。
-- **高性能**
+# 发布版本
- Java Chassis 网络层基于 [Vert.x](https://vertx.io) 实现, 支持开发者使用[响应式编程](https://www.reactivemanifesto.org), 开发者在使用熟悉的REST风格设计业务接口的时候,也能够获取到非常高性能的吞吐量。同时还提供了Highway协议,满足更高性能场景的要求。
+| 版本火车 | 最新版本 | 编译的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 | 停止更新 |
-- **原生支持OpenAPI**
+Java Chassis 的核心依赖
- Java Chassis 的接口开发、服务治理都基于 [Swagger](https://swagger.io) ,并通过接口语义检查,使得接口定义符合 [OpenAPI 规范](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 |
-- **灵活的开发方式**
+> NOTICE: Open API 3.0.x 不兼容 2.0.x, 因此Java Chassis 2、Java Chassis 1不能与Java Chassis 3共存互访. 升级Java Chassis 3, 需要将相关的消费者、提供者和边缘服务同时升级.
- 开发者可以使用 `SpringMVC`/`JAX-RS`/`transparent RPC` 任意一种方式定义服务端接口, 并使用`RPC`/`RestTemplate` 等方式访问这些接口. 得益于Java Chassis的通信层与开发方式分离的设计,开发者可以在 `Rest over Vertx`/`Rest over Servlet`/`Highway`等通信模式下自由切换.
+> NOTICE: Java Chassis 1 第一个版本于2018发布,已经停止更新.
-- **开箱即用的服务治理能力**
+# 快速开始
- Java Chassis 提供了大量开箱即用的服务治理能力,包括服务发现、熔断容错、负载均衡、流量控制等。
+* 定义服务契约
+```java
+@RequestMapping(path = "/provider")
+public interface ProviderService {
+ @GetMapping("/sayHello")
+ String sayHello(@RequestParam("name") String name);
+}
+```
-# 快速开始
+* 定义提供者
-定义提供者:
```java
-import org.apache.servicecomb.*;
-@RpcSchema(schemaId = "helloworld")
-public class HelloWorldProvider implements HelloWorld {
- public String sayHello(String name) {
- return "Hello " + name;
- }
+@RestSchema(schemaId = "ProviderController", schemaInterface = ProviderService.class)
+public class ProviderController implements ProviderService {
+ @Override
+ public String sayHello(String name) {
+ return "Hello " + name;
+ }
}
```
-定义消费者:
+* 定义消费者
+
+```java
+@Configuration
+public class ProviderServiceConfiguration {
+ @Bean
+ public ProviderService providerService() {
+ return Invoker.createProxy("provider", "ProviderController", ProviderService.class);
+ }
+}
+```
+
+使用RPC方式访问提供者。
+
```java
-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]: https://docs.servicecomb.io/java-chassis/zh_CN/
+[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
@@ -70,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)
# 参与代码提交
@@ -94,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 eae0590e419..00000000000
--- a/archetypes/business-service-jaxrs/pom.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
-
-
- org.apache.servicecomb
- archetypes
- 2.3.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 47d2b54c8ed..00000000000
--- a/archetypes/business-service-pojo/pom.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
-
-
- org.apache.servicecomb
- archetypes
- 2.3.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 632b82d2672..00000000000
--- a/archetypes/business-service-spring-boot2-starter/pom.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
-
-
- org.apache.servicecomb
- archetypes
- 2.3.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 5f90f5bd124..00000000000
--- a/archetypes/business-service-springmvc/pom.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
-
-
- org.apache.servicecomb
- archetypes
- 2.3.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 b35162d8cc9..00000000000
--- a/archetypes/pom.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
- 4.0.0
-
- org.apache.servicecomb
- java-chassis-parent
- 2.3.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 70e393d3b9a..e7e2fa1fc2b 100644
--- a/clients/config-center-client/pom.xml
+++ b/clients/config-center-client/pom.xml
@@ -22,7 +22,7 @@
clientsorg.apache.servicecomb
- 2.3.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 fb4e7ef20e8..00000000000
--- a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/AddressManager.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.servicecomb.config.center.client;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-
-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;
-
- 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))));
- this.index = new Random().nextInt(addresses.size());
- }
-
- private String formatAddress(String address) {
- try {
- return address + "/v3/" + HttpUtils.encodeURLParam(this.projectName);
- } catch (Exception e) {
- throw new IllegalStateException("not possible");
- }
- }
-
- public String nextAddress() {
- synchronized (this) {
- this.index++;
- if (this.index >= addresses.size()) {
- this.index = 0;
- }
- }
- return address();
- }
-
- public String address() {
- synchronized (this) {
- return addresses.get(index);
- }
- }
-}
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 c362804aad2..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,32 @@
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);
+
public static final String DEFAULT_APP_SEPARATOR = "@";
public static final String DEFAULT_SERVICE_SEPARATOR = "#";
@@ -42,29 +52,47 @@ public class ConfigCenterClient implements ConfigCenterOperation {
public static final String APPLICATION_CONFIG = "application";
- private HttpTransport httpTransport;
+ public static final String DARK_LAUNCH = "darklaunch@";
+
+ private static final String ADDRESS_CHECK_PATH = "/v3/default/configuration/health?mode=readiness";
+
+ private final HttpTransport httpTransport;
+
+ private final ConfigCenterAddressManager addressManager;
- private AddressManager addressManager;
+ private final Map> dimensionConfigNames = new HashMap<>();
- public ConfigCenterClient(AddressManager addressManager, HttpTransport httpTransport) {
+ 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();
Map configurations = new HashMap<>();
+
+ String uri = null;
try {
+ uri = address + "/configuration/items?dimensionsInfo="
+ + HttpUtils.encodeURLParam(dimensionsInfo) + "&revision=" + request.getRevision();
+
Map headers = new HashMap<>();
headers.put("x-environment", request.getEnvironment());
- HttpRequest httpRequest = new HttpRequest(addressManager.address() + "/configuration/items?dimensionsInfo="
- + HttpUtils.encodeURLParam(dimensionsInfo) + "&revision=" + request.getRevision(), headers, null,
+ HttpRequest httpRequest = new HttpRequest(uri, headers, null,
HttpRequest.GET);
HttpResponse httpResponse = httpTransport.doRequest(httpRequest);
+ recordAndSendUnAuthorizedEvent(httpResponse, address);
if (httpResponse.getStatusCode() == HttpStatus.SC_OK) {
Map> allConfigMap = HttpUtils.deserialize(
httpResponse.getContent(),
@@ -77,14 +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);
@@ -92,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 {
@@ -104,11 +146,59 @@ public QueryConfigurationsResponse queryConfigurations(QueryConfigurationsReques
+ httpResponse.getContent());
}
} catch (IOException e) {
- addressManager.nextAddress();
+ 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
@@ -119,4 +209,8 @@ private String buildDimensionsInfo(QueryConfigurationsRequest request, boolean w
}
return result;
}
+
+ private String buildDarkLaunchDimensionsInfo(QueryConfigurationsRequest request) {
+ return DARK_LAUNCH + request.getApplication();
+ }
}
diff --git a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterConfigurationChangedEvent.java b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterConfigurationChangedEvent.java
new file mode 100644
index 00000000000..448c51a3d79
--- /dev/null
+++ b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterConfigurationChangedEvent.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.config.center.client;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * This event is fired when configuration changed of config center.
+ */
+public class ConfigCenterConfigurationChangedEvent {
+ private final Map added;
+
+ private final Map deleted;
+
+ private final Map updated;
+
+ private Set changed;
+
+ private ConfigCenterConfigurationChangedEvent(Map added, Map updated,
+ Map deleted) {
+ this.added = added;
+ this.deleted = deleted;
+ this.updated = updated;
+ this.changed = new HashSet<>();
+ this.changed.addAll(added.keySet());
+ this.changed.addAll(updated.keySet());
+ this.changed.addAll(deleted.keySet());
+ }
+
+ public static ConfigCenterConfigurationChangedEvent createIncremental(Map latest,
+ Map last) {
+ Map itemsCreated = new HashMap<>();
+ Map itemsDeleted = new HashMap<>();
+ Map itemsModified = new HashMap<>();
+
+ for (Map.Entry entry : latest.entrySet()) {
+ String itemKey = entry.getKey();
+ if (!last.containsKey(itemKey)) {
+ itemsCreated.put(itemKey, entry.getValue());
+ } else if (!Objects.equals(last.get(itemKey), latest.get(itemKey))) {
+ itemsModified.put(itemKey, entry.getValue());
+ }
+ }
+ for (String itemKey : last.keySet()) {
+ if (!latest.containsKey(itemKey)) {
+ itemsDeleted.put(itemKey, null);
+ }
+ }
+ ConfigCenterConfigurationChangedEvent event = ConfigCenterConfigurationChangedEvent
+ .createIncremental(itemsCreated, itemsModified, itemsDeleted);
+ return event;
+ }
+
+ public static ConfigCenterConfigurationChangedEvent createIncremental(Map added,
+ Map updated,
+ Map deleted) {
+ return new ConfigCenterConfigurationChangedEvent(added, updated, deleted);
+ }
+
+ public static ConfigCenterConfigurationChangedEvent createIncremental(Map updated) {
+ return new ConfigCenterConfigurationChangedEvent(new HashMap<>(), updated, new HashMap<>());
+ }
+
+ public final Map getAdded() {
+ return added;
+ }
+
+
+ public final Map getUpdated() {
+ return updated;
+ }
+
+
+ public final Map getDeleted() {
+ return deleted;
+ }
+
+ public final Set getChanged() {
+ return changed;
+ }
+}
diff --git a/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterManager.java b/clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterManager.java
index ab63198bb3c..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.Collections;
+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.ConfigurationChangedEvent;
+import org.apache.servicecomb.config.common.ConfigConverter;
import org.apache.servicecomb.http.client.task.AbstractTask;
import org.apache.servicecomb.http.client.task.Task;
import org.slf4j.Logger;
@@ -34,26 +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 Map lastConfiguration;
+ private final ConfigConverter configConverter;
- public ConfigCenterManager(ConfigCenterClient configCenterClient, EventBus eventBus) {
- this(configCenterClient, eventBus, Collections.emptyMap());
- }
+ private final ConfigCenterConfiguration configCenterConfiguration;
+
+ private final ConfigCenterAddressManager configCenterAddressManager;
- public ConfigCenterManager(ConfigCenterClient configCenterClient, EventBus eventBus,
- Map lastConfiguration) {
+ public ConfigCenterManager(ConfigCenterClient configCenterClient, EventBus eventBus, ConfigConverter configConverter,
+ ConfigCenterConfiguration configCenterConfiguration, ConfigCenterAddressManager configCenterAddressManager) {
super("config-center-configuration-task");
this.configCenterClient = configCenterClient;
this.eventBus = eventBus;
- this.lastConfiguration = lastConfiguration;
+ this.configConverter = configConverter;
+ this.configCenterConfiguration = configCenterConfiguration;
+ this.configCenterAddressManager = configCenterAddressManager;
}
public void setQueryConfigurationsRequest(QueryConfigurationsRequest queryConfigurationsRequest) {
@@ -62,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 {
@@ -74,17 +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());
- eventBus.post(ConfigurationChangedEvent.createIncremental(response.getConfigurations(), lastConfiguration));
- lastConfiguration = response.getConfigurations();
+ Map lastData = configConverter.updateData(response.getConfigurations());
+ ConfigCenterConfigurationChangedEvent event = ConfigCenterConfigurationChangedEvent
+ .createIncremental(configConverter.getCurrentData(), lastData);
+ 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 4450d22f6ba..ff10b993583 100644
--- a/clients/config-common/pom.xml
+++ b/clients/config-common/pom.xml
@@ -22,7 +22,7 @@
clientsorg.apache.servicecomb
- 2.3.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
new file mode 100644
index 00000000000..0d8973d8aeb
--- /dev/null
+++ b/clients/config-common/src/main/java/org/apache/servicecomb/config/common/ConfigConverter.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.config.common;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
+import org.springframework.core.io.ByteArrayResource;
+import org.springframework.util.CollectionUtils;
+
+public class ConfigConverter {
+ private Map currentData = Collections.emptyMap();
+
+ private Map lastRawData;
+
+ private final List fileSources;
+
+ public ConfigConverter(List fileSources) {
+ this.fileSources = fileSources;
+ }
+
+ public Map getLastRawData() {
+ return this.lastRawData;
+ }
+
+ public Map getCurrentData() {
+ return this.currentData;
+ }
+
+ public Map updateData(Map rawData) {
+ Map lastData = this.currentData;
+
+ this.lastRawData = rawData;
+
+ if (CollectionUtils.isEmpty(fileSources)) {
+ this.currentData = rawData;
+ return lastData;
+ }
+
+ Map fileProperties = new HashMap<>();
+ fileSources.forEach(source -> {
+ if (rawData.get(source) != null) {
+ fileProperties.put(source, rawData.get(source));
+ }
+ });
+
+ Map result = new HashMap<>(rawData.size());
+ result.putAll(rawData);
+ fileProperties.forEach((k, v) -> result.putAll(createFileSource(v)));
+ this.currentData = result;
+ return lastData;
+ }
+
+ private Map createFileSource(Object v) {
+ YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean();
+ yamlFactory.setResources(new ByteArrayResource(v.toString().getBytes(StandardCharsets.UTF_8)));
+ return propertiesToMap(yamlFactory.getObject());
+ }
+
+ @SuppressWarnings("unchecked")
+ private Map propertiesToMap(Properties properties) {
+ if (properties == null) {
+ return Collections.emptyMap();
+ }
+ Map result = new HashMap<>();
+ Enumeration keys = (Enumeration) properties.propertyNames();
+ while (keys.hasMoreElements()) {
+ String key = keys.nextElement();
+ Object value = properties.getProperty(key);
+ result.put(key, value);
+ }
+ return result;
+ }
+}
diff --git a/clients/config-common/src/main/java/org/apache/servicecomb/config/common/ConfigurationChangedEvent.java b/clients/config-common/src/main/java/org/apache/servicecomb/config/common/ConfigurationChangedEvent.java
deleted file mode 100644
index 6f0ca00c10e..00000000000
--- a/clients/config-common/src/main/java/org/apache/servicecomb/config/common/ConfigurationChangedEvent.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.servicecomb.config.common;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class ConfigurationChangedEvent {
- private final Map added;
-
- private final Map deleted;
-
- private final Map updated;
-
- private ConfigurationChangedEvent(Map added, Map updated,
- Map deleted) {
- this.added = added;
- this.deleted = deleted;
- this.updated = updated;
- }
-
- public static ConfigurationChangedEvent createIncremental(Map latest, Map last) {
- Map itemsCreated = new HashMap<>();
- Map itemsDeleted = new HashMap<>();
- Map itemsModified = new HashMap<>();
-
- for (String itemKey : latest.keySet()) {
- if (!last.containsKey(itemKey)) {
- itemsCreated.put(itemKey, latest.get(itemKey));
- } else if (!last.get(itemKey).equals(latest.get(itemKey))) {
- itemsModified.put(itemKey, latest.get(itemKey));
- }
- }
- for (String itemKey : last.keySet()) {
- if (!latest.containsKey(itemKey)) {
- itemsDeleted.put(itemKey, "");
- }
- }
- return ConfigurationChangedEvent.createIncremental(itemsCreated, itemsModified, itemsDeleted);
- }
-
- public static ConfigurationChangedEvent createIncremental(Map added, Map updated,
- Map deleted) {
- return new ConfigurationChangedEvent(added, updated, deleted);
- }
-
- public final Map getAdded() {
- return added;
- }
-
-
- public final Map getUpdated() {
- return updated;
- }
-
-
- public final Map getDeleted() {
- return deleted;
- }
-
- public final Map getComplete() {
- Map result = new HashMap<>(added.size() + updated.size());
- result.putAll(added);
- result.putAll(updated);
- return result;
- }
-}
diff --git a/clients/config-common/src/main/java/org/apache/servicecomb/config/common/exception/OperationException.java b/clients/config-common/src/main/java/org/apache/servicecomb/config/common/exception/OperationException.java
new file mode 100644
index 00000000000..f4e26b50505
--- /dev/null
+++ b/clients/config-common/src/main/java/org/apache/servicecomb/config/common/exception/OperationException.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.config.common.exception;
+
+public class OperationException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ public OperationException(String message) {
+ super(message);
+ }
+
+ public OperationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/clients/config-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 7e3e81ed0b7..00000000000
--- a/clients/config-common/src/test/java/org/apache/servicecomb/config/common/TestConfigurationChangedEvent.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.servicecomb.config.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");
- after.put("added", 1);
- after.put("updated", 2);
- ConfigurationChangedEvent event = ConfigurationChangedEvent.createIncremental(after, before);
- Assert.assertEquals(1, event.getAdded().size());
- Assert.assertEquals(1, event.getDeleted().size());
- Assert.assertEquals(1, event.getUpdated().size());
- Assert.assertEquals(2, event.getComplete().size());
- }
-}
diff --git a/clients/config-kie-client/pom.xml b/clients/config-kie-client/pom.xml
index 5bbcb0f8f80..30dac44ba53 100644
--- a/clients/config-kie-client/pom.xml
+++ b/clients/config-kie-client/pom.xml
@@ -22,7 +22,7 @@
clientsorg.apache.servicecomb
- 2.3.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 6b249696599..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,95 +17,91 @@
package org.apache.servicecomb.config.kie.client;
-import org.apache.commons.lang3.StringUtils;
+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;
import org.apache.servicecomb.config.kie.client.model.KVDoc;
import org.apache.servicecomb.config.kie.client.model.KVResponse;
import org.apache.servicecomb.config.kie.client.model.KieAddressManager;
+import org.apache.servicecomb.config.kie.client.model.KieConfiguration;
import org.apache.servicecomb.config.kie.client.model.ValueType;
import org.apache.servicecomb.http.client.common.HttpRequest;
import org.apache.servicecomb.http.client.common.HttpResponse;
import org.apache.servicecomb.http.client.common.HttpTransport;
import org.apache.servicecomb.http.client.common.HttpUtils;
+import org.apache.servicecomb.http.client.event.OperationEvents.UnAuthorizedOperationEvent;
+import org.apache.servicecomb.http.client.utils.ServiceCombServiceAvailableUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.io.ByteArrayResource;
-
-import java.io.StringReader;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.concurrent.atomic.AtomicBoolean;
+import org.springframework.util.CollectionUtils;
public class KieClient implements KieConfigOperation {
private static final Logger LOGGER = LoggerFactory.getLogger(KieClient.class);
- private AtomicBoolean isFirst = new AtomicBoolean(true);
+ private static final String ADDRESS_CHECK_PATH = "/v1/health";
protected HttpTransport httpTransport;
protected String revision = "0";
- private String url;
+ private final KieAddressManager addressManager;
- private HttpResponse httpResponse = null;
+ private final KieConfiguration kieConfiguration;
- private KieAddressManager addressManager;
+ public static final String DEFAULT_KIE_API_VERSION = "v1";
- private Map labelsMap;
+ private final Map> dimensionConfigNames = new HashMap<>();
- public static final String DEFAULT_KIE_API_VERSION = "v1";
+ private EventBus eventBus;
- public KieClient(KieAddressManager addressManager, HttpTransport httpTransport) {
+ public KieClient(KieAddressManager addressManager, HttpTransport httpTransport, KieConfiguration kieConfiguration) {
this.httpTransport = httpTransport;
this.addressManager = addressManager;
+ this.kieConfiguration = kieConfiguration;
+ }
+
+ public void setEventBus(EventBus eventBus) {
+ this.eventBus = eventBus;
+ addressManager.setEventBus(eventBus);
}
@Override
- public ConfigurationsResponse queryConfigurations(ConfigurationsRequest request) {
- boolean isWatch = false;
- if (Boolean.valueOf(getPropertiesValue(getConfigKeyValue(ConfigConstants.KEY_ENABLELONGPOLLING)))) {
- isWatch = true;
- }
+ public ConfigurationsResponse queryConfigurations(ConfigurationsRequest request, String address) {
+ String url = buildUrl(request, address);
try {
- url = addressManager.address()
- + "/"
- + DEFAULT_KIE_API_VERSION
- + "/"
- + getPropertiesValue(getConfigKeyValue(ConfigConstants.KEY_PROJECT))
- + "/kie/kv?label=app:"
- //app 名称作为筛选条件
- + request.getApplication()
- + "&revision="
- + revision;
-
- if (isWatch && !isFirst.get()) {
- url +=
- "&wait=" + getPropertiesValue(getConfigKeyValue(ConfigConstants.KEY_POLLINGWAITSEC)) + "s";
- }
- isFirst.compareAndSet(true, false);
- Map headers = new HashMap<>();
- headers.put("environment", request.getEnvironment());
- HttpRequest httpRequest = new HttpRequest(url, headers, null, HttpRequest.GET);
- httpResponse = httpTransport.doRequest(httpRequest);
- if (httpResponse == null) {
- return null;
+ if (kieConfiguration.isEnableLongPolling()) {
+ url += "&wait=" + kieConfiguration.getPollingWaitInSeconds() + "s";
}
+
+ HttpRequest httpRequest = new HttpRequest(url, null, null, HttpRequest.GET);
+ HttpResponse httpResponse = httpTransport.doRequest(httpRequest);
+ recordAndSendUnAuthorizedEvent(httpResponse, address);
ConfigurationsResponse configurationsResponse = new ConfigurationsResponse();
if (httpResponse.getStatusCode() == HttpStatus.SC_OK) {
revision = httpResponse.getHeader("X-Kie-Revision");
KVResponse allConfigList = HttpUtils.deserialize(httpResponse.getContent(), KVResponse.class);
- Map configurations = getConfigByLabel(allConfigList, request);
+ logConfigurationNames(request.getLabelsQuery(), allConfigList.getData());
+ Map configurations = getConfigByLabel(allConfigList);
configurationsResponse.setConfigurations(configurations);
configurationsResponse.setChanged(true);
configurationsResponse.setRevision(revision);
@@ -118,83 +114,115 @@ 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.nextAddress();
+ addressManager.recordFailState(address);
+ LOGGER.error("query configuration from {} failed, message={}", url, e.getMessage());
throw new OperationException("read response failed. ", e);
}
}
- private Map getConfigByLabel(KVResponse resp, ConfigurationsRequest request) {
- Map resultMap = new HashMap<>();
- List appList = new ArrayList<>();
- List serviceList = new ArrayList<>();
- List versionList = new ArrayList<>();
- for (KVDoc kvDoc : resp.getData()) {
- if (!StringUtils.isEmpty(kvDoc.getStatus()) && !kvDoc.getStatus()
- .equals(ConfigConstants.STATUS_ENABLED)) {
- continue;
- }
- labelsMap = kvDoc.getLabels();
- boolean checkApplication = checkValue(ConfigConstants.LABEL_APP, request.getApplication());
- boolean checkEnvironment = checkValue(ConfigConstants.LABEL_ENV, request.getEnvironment());
- boolean checkServer = checkValue(ConfigConstants.LABEL_SERVICE, request.getServiceName());
- boolean checkVersion = checkValue(ConfigConstants.LABEL_VERSION, request.getVersion());
- if (checkApplication && checkEnvironment && !labelsMap.containsKey(ConfigConstants.LABEL_SERVICE)) {
- appList.add(kvDoc);
- }
- if (checkApplication && checkEnvironment && checkServer && !kvDoc.getLabels().containsKey(ConfigConstants.LABEL_VERSION)) {
- serviceList.add(kvDoc);
- }
- if (checkApplication && checkEnvironment && checkServer && checkVersion) {
- versionList.add(kvDoc);
- }
+ 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);
}
- //kv is priority
- for (KVDoc kvDoc : appList) {
- resultMap.putAll(processValueType(kvDoc));
+ }
+
+ /**
+ * 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;
}
- for (KVDoc kvDoc : serviceList) {
- resultMap.putAll(processValueType(kvDoc));
+ List configNames = dimensionConfigNames.get(dimension);
+ if (configNames == null) {
+ configNames = new ArrayList<>();
}
- for (KVDoc kvDoc : versionList) {
- resultMap.putAll(processValueType(kvDoc));
+ StringBuilder names = new StringBuilder();
+ for (KVDoc doc : data) {
+ if (configNames.contains(doc.getKey())) {
+ continue;
+ }
+ names.append(doc.getKey()).append(",");
+ configNames.add(doc.getKey());
}
- return resultMap;
+ 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);
}
- private boolean checkValue(String key, String propertyName) {
- if (!labelsMap.containsKey(key)) {
- return false;
- }
- if (!labelsMap.get(key).equals(propertyName)) {
- return false;
+ @Override
+ public void checkAddressAvailable(String address) {
+ ServiceCombServiceAvailableUtils.checkAddressAvailable(addressManager, address, httpTransport, ADDRESS_CHECK_PATH);
+ }
+
+ private String buildUrl(ConfigurationsRequest request, String currentAddress) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(currentAddress);
+ sb.append("/");
+ sb.append(DEFAULT_KIE_API_VERSION);
+ sb.append("/");
+ sb.append(kieConfiguration.getProject());
+ sb.append("/kie/kv?");
+ sb.append(request.getLabelsQuery());
+ sb.append("&revision=");
+ sb.append(request.getRevision());
+ if (request.isWithExact()) {
+ sb.append("&match=exact");
}
- return true;
+ return sb.toString();
+ }
+
+ private Map getConfigByLabel(KVResponse resp) {
+ Map resultMap = new HashMap<>();
+ resp.getData().stream()
+ .sorted(Comparator.comparing(KVDoc::getUpdateTime, Comparator.nullsFirst(Comparator.naturalOrder())))
+ .filter(doc -> doc.getStatus() == null || ConfigConstants.STATUS_ENABLED.equalsIgnoreCase(doc.getStatus()))
+ .map(this::processValueType)
+ .collect(Collectors.toList())
+ .forEach(resultMap::putAll);
+ return resultMap;
}
private Map processValueType(KVDoc kvDoc) {
- ValueType vtype;
+ ValueType valueType;
try {
- vtype = ValueType.valueOf(kvDoc.getValueType());
+ 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<>();
try {
- switch (vtype) {
+ switch (valueType) {
case yml:
case yaml:
YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean();
- yamlFactory.setResources(new ByteArrayResource(kvDoc.getValue().getBytes()));
- return toMap(kvDoc.getKey(), yamlFactory.getObject());
+ yamlFactory.setResources(new ByteArrayResource(kvDoc.getValue().getBytes(StandardCharsets.UTF_8)));
+ return toMap(yamlFactory.getObject());
case properties:
properties.load(new StringReader(kvDoc.getValue()));
- return toMap(kvDoc.getKey(), properties);
+ return toMap(properties);
case text:
case string:
default:
@@ -202,13 +230,13 @@ private Map processValueType(KVDoc kvDoc) {
return kvMap;
}
} catch (Exception e) {
- LOGGER.error("read config failed");
+ LOGGER.error("read config failed", e);
}
return Collections.emptyMap();
}
@SuppressWarnings("unchecked")
- private Map toMap(String prefix, Properties properties) {
+ private Map toMap(Properties properties) {
if (properties == null) {
return Collections.emptyMap();
}
@@ -217,23 +245,8 @@ private Map toMap(String prefix, Properties properties) {
while (keys.hasMoreElements()) {
String key = keys.nextElement();
Object value = properties.getProperty(key);
- if (!StringUtils.isEmpty(prefix)) {
- key = prefix + "." + key;
- }
- if (value != null) {
- result.put(key, value);
- } else {
- result.put(key, null);
- }
+ result.put(key, value);
}
return result;
}
-
- private String getPropertiesValue(String key) {
- return this.addressManager.getProperties().getProperty(key);
- }
-
- private String getConfigKeyValue(String key) {
- return this.addressManager.getConfigKey().get(key);
- }
}
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 f636ffef6d7..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
@@ -17,12 +17,17 @@
package org.apache.servicecomb.config.kie.client;
-import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.concurrent.Executors;
-import org.apache.servicecomb.config.common.ConfigurationChangedEvent;
+import org.apache.servicecomb.config.common.ConfigConverter;
import org.apache.servicecomb.config.kie.client.model.ConfigurationsRequest;
+import org.apache.servicecomb.config.kie.client.model.ConfigurationsRequestFactory;
import org.apache.servicecomb.config.kie.client.model.ConfigurationsResponse;
+import org.apache.servicecomb.config.kie.client.model.KieAddressManager;
+import org.apache.servicecomb.config.kie.client.model.KieConfiguration;
import org.apache.servicecomb.http.client.task.AbstractTask;
import org.apache.servicecomb.http.client.task.Task;
import org.slf4j.Logger;
@@ -34,57 +39,140 @@ 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 ConfigurationsRequest configurationsRequest;
+ private final ConfigConverter configConverter;
- private Map lastConfiguration;
+ private final List configurationsRequests;
- public KieConfigManager(KieConfigOperation configKieClient, EventBus eventBus) {
- this(configKieClient, eventBus, Collections.emptyMap());
- }
+ private final KieConfiguration kieConfiguration;
+
+ private final KieAddressManager kieAddressManager;
public KieConfigManager(KieConfigOperation configKieClient, EventBus eventBus,
- Map lastConfiguration) {
+ KieConfiguration kieConfiguration, ConfigConverter configConverter, KieAddressManager kieAddressManager) {
super("config-center-configuration-task");
+ this.configurationsRequests = ConfigurationsRequestFactory.buildConfigurationRequests(kieConfiguration);
+ this.configurationsRequests.sort(ConfigurationsRequest::compareTo);
this.configKieClient = configKieClient;
this.eventBus = eventBus;
- this.lastConfiguration = lastConfiguration;
+ this.configConverter = configConverter;
+ this.kieConfiguration = kieConfiguration;
+ this.kieAddressManager = kieAddressManager;
}
- public void setConfigurationsRequest(ConfigurationsRequest configurationsRequest) {
- this.configurationsRequest = configurationsRequest;
+ public void firstPull() {
+ Map data = new HashMap<>();
+ try {
+ firstQueryConfigurations(data);
+ } catch (Exception e) {
+ if (this.kieConfiguration.isFirstPullRequired()) {
+ throw e;
+ } else {
+ LOGGER.warn("first pull failed!");
+ }
+ }
+ }
+
+ private void firstQueryConfigurations(Map data) {
+ for (int i = 0; i < 3;) {
+ String address = kieAddressManager.address();
+ try {
+ this.configurationsRequests.forEach(r -> {
+ r.setRevision(ConfigurationsRequest.INITIAL_REVISION);
+ ConfigurationsResponse response = configKieClient.queryConfigurations(r, address);
+ if (response.isChanged()) {
+ r.setRevision(response.getRevision());
+ r.setLastRawData(response.getConfigurations());
+ data.putAll(response.getConfigurations());
+ }
+ });
+ this.configConverter.updateData(data);
+ break;
+ } catch (Exception e) {
+ if (i == 2) {
+ throw e;
+ }
+ LOGGER.warn("firstQueryConfigurations failed, config address {} and ignore {}", address, e.getMessage());
+ }
+ i++;
+ }
+ }
+
+ private void onDataChanged() {
+ Map latestData = new HashMap<>();
+ this.configurationsRequests.forEach(r -> latestData.putAll(r.getLastRawData()));
+
+ Map lastData = configConverter.updateData(latestData);
+ KieConfigurationChangedEvent event = KieConfigurationChangedEvent
+ .createIncremental(configConverter.getCurrentData(), lastData);
+ if (!event.getChanged().isEmpty()) {
+ eventBus.post(event);
+ }
+ }
+
+ @Override
+ protected void initTaskPool(String taskName) {
+ this.taskPool = Executors.newFixedThreadPool(3, (task) ->
+ new Thread(task, taskName));
}
public void startConfigKieManager() {
- this.startTask(new PollConfigurationTask(0));
+ this.configurationsRequests.forEach((t) ->
+ this.startTask(new PollConfigurationTask(0, t)));
+ schedulerCheckAddressAvailable("kie-addr-check", new CheckKieAddressTask(),
+ kieConfiguration.getRefreshIntervalInMillis());
}
class PollConfigurationTask implements Task {
- int failCount = 0;
+ final int failCount;
+
+ ConfigurationsRequest configurationsRequest;
- public PollConfigurationTask(int failCount) {
+ public PollConfigurationTask(int failCount, ConfigurationsRequest configurationsRequest) {
this.failCount = failCount;
+ this.configurationsRequest = configurationsRequest;
}
@Override
public void execute() {
try {
- ConfigurationsResponse response = configKieClient.queryConfigurations(configurationsRequest);
+ ConfigurationsResponse response = configKieClient.queryConfigurations(configurationsRequest,
+ kieAddressManager.address());
if (response.isChanged()) {
- LOGGER.info("The configurations are change, will refresh local configurations.");
configurationsRequest.setRevision(response.getRevision());
- eventBus.post(ConfigurationChangedEvent.createIncremental(response.getConfigurations(), lastConfiguration));
- lastConfiguration = response.getConfigurations();
+ configurationsRequest.setLastRawData(response.getConfigurations());
+ onDataChanged();
+ }
+ if (KieConfigManager.this.kieConfiguration.isEnableLongPolling()) {
+ startTask(
+ new BackOffSleepTask(LONG_POLLING_INTERVAL, new PollConfigurationTask(0, this.configurationsRequest)));
+ } else {
+ startTask(new BackOffSleepTask(kieConfiguration.getRefreshIntervalInMillis(),
+ new PollConfigurationTask(0, this.configurationsRequest)));
}
- startTask(new BackOffSleepTask(POLL_INTERVAL, new PollConfigurationTask(0)));
} catch (Exception e) {
- LOGGER.error("get configurations from KieConfigCenter failed, and will try again.", e);
- startTask(new BackOffSleepTask(failCount + 1, new PollConfigurationTask(failCount + 1)));
+ 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 15233342ff8..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,59 +17,70 @@
package org.apache.servicecomb.config.kie.client.model;
-public class ConfigurationsRequest {
- private String environment;
+import java.util.HashMap;
+import java.util.Map;
- private String application;
+public class ConfigurationsRequest implements Comparable {
+ public static final String INITIAL_REVISION = "-1";
- private String serviceName;
+ private int order;
- private String version;
+ private String revision = INITIAL_REVISION;
- private String revision;
+ private boolean withExact;
- public String getEnvironment() {
- return environment;
+ private String labelsQuery;
+
+ private Map lastRawData = new HashMap<>();
+
+ public int getOrder() {
+ return order;
}
- public ConfigurationsRequest setEnvironment(String environment) {
- this.environment = environment;
+ public ConfigurationsRequest setOrder(int order) {
+ this.order = order;
return this;
}
- public String getApplication() {
- return application;
+ public String getRevision() {
+ return revision;
}
- public ConfigurationsRequest setApplication(String application) {
- this.application = application;
+ public ConfigurationsRequest setRevision(String revision) {
+ this.revision = revision;
return this;
}
- public String getServiceName() {
- return serviceName;
+ public boolean isWithExact() {
+ return withExact;
}
- public ConfigurationsRequest setServiceName(String serviceName) {
- this.serviceName = serviceName;
+ public ConfigurationsRequest setWithExact(boolean withExact) {
+ this.withExact = withExact;
return this;
}
- public String getVersion() {
- return version;
+ public String getLabelsQuery() {
+ return labelsQuery;
}
- public ConfigurationsRequest setVersion(String version) {
- this.version = version;
+ public ConfigurationsRequest setLabelsQuery(String labelsQuery) {
+ this.labelsQuery = labelsQuery;
return this;
}
- public String getRevision() {
- return revision;
+ public Map getLastRawData() {
+ return lastRawData;
}
- public ConfigurationsRequest setRevision(String revision) {
- this.revision = revision;
+ public ConfigurationsRequest setLastRawData(Map lastRawData) {
+ this.lastRawData = lastRawData;
return this;
}
+
+ @Override
+ public int compareTo(ConfigurationsRequest o) {
+ // Higher priority, query the last
+ return o.getOrder() - this.order;
+ }
}
diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsRequestFactory.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsRequestFactory.java
new file mode 100644
index 00000000000..20c6ba3bacb
--- /dev/null
+++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/ConfigurationsRequestFactory.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.config.kie.client.model;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.servicecomb.http.client.common.HttpUtils;
+
+public class ConfigurationsRequestFactory {
+ private static final String KEY_APP = "app";
+
+ private static final String KEY_ENVIRONMENT = "environment";
+
+ private static final String KEY_SERVICE = "service";
+
+ private static final String KEY_VERSION = "version";
+
+ private static final int CUSTOM_ORDER = 100;
+
+ private static final int VERSION_ORDER = 200;
+
+ private static final int SERVICE_ORDER = 300;
+
+ private static final int APP_ORDER = 400;
+
+ public static List buildConfigurationRequests(KieConfiguration configuration) {
+ List result = new ArrayList<>();
+ if (configuration.isEnableAppConfig()) {
+ result.add(createAppConfigurationsRequest(configuration));
+ }
+ if (configuration.isEnableServiceConfig()) {
+ result.add(createServiceConfigurationsRequest(configuration));
+ }
+ if (configuration.isEnableVersionConfig()) {
+ result.add(createVersionConfigurationsRequest(configuration));
+ }
+ if (configuration.isEnableCustomConfig()) {
+ result.add(createCustomConfigurationsRequest(configuration));
+ }
+ return result;
+ }
+
+ private static ConfigurationsRequest createAppConfigurationsRequest(KieConfiguration configuration) {
+ return new ConfigurationsRequest()
+ .setOrder(APP_ORDER)
+ .setWithExact(true)
+ .setLabelsQuery(buildLabelQuery(buildLabelQueryItem(KEY_APP, configuration.getAppName()),
+ buildLabelQueryItem(KEY_ENVIRONMENT, configuration.getEnvironment())));
+ }
+
+ private static ConfigurationsRequest createServiceConfigurationsRequest(KieConfiguration configuration) {
+ return new ConfigurationsRequest()
+ .setOrder(SERVICE_ORDER)
+ .setWithExact(true)
+ .setLabelsQuery(buildLabelQuery(buildLabelQueryItem(KEY_APP, configuration.getAppName()),
+ buildLabelQueryItem(KEY_SERVICE, configuration.getServiceName()),
+ buildLabelQueryItem(KEY_ENVIRONMENT, configuration.getEnvironment())));
+ }
+
+ private static ConfigurationsRequest createVersionConfigurationsRequest(KieConfiguration configuration) {
+ return new ConfigurationsRequest()
+ .setOrder(VERSION_ORDER)
+ .setWithExact(true)
+ .setLabelsQuery(buildLabelQuery(buildLabelQueryItem(KEY_APP, configuration.getAppName()),
+ buildLabelQueryItem(KEY_SERVICE, configuration.getServiceName()),
+ buildLabelQueryItem(KEY_ENVIRONMENT, configuration.getEnvironment()),
+ buildLabelQueryItem(KEY_VERSION, configuration.getVersion())));
+ }
+
+ private static ConfigurationsRequest createCustomConfigurationsRequest(KieConfiguration configuration) {
+ return new ConfigurationsRequest()
+ .setOrder(CUSTOM_ORDER)
+ .setWithExact(false)
+ .setLabelsQuery(
+ buildLabelQuery(buildLabelQueryItem(configuration.getCustomLabel(), configuration.getCustomLabelValue())));
+ }
+
+ private static String buildLabelQuery(String... labels) {
+ StringBuilder result = new StringBuilder();
+ for (String label : labels) {
+ result.append(label);
+ result.append("&");
+ }
+ return result.toString();
+ }
+
+ private static String buildLabelQueryItem(String key, String value) {
+ try {
+ return "label=" + HttpUtils.encodeURLParam(key + ":" + value);
+ } catch (IOException e) {
+ throw new IllegalArgumentException("unexpected param", e);
+ }
+ }
+}
diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/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 1b32be6c6ae..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,51 +17,23 @@
package org.apache.servicecomb.config.kie.client.model;
-import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Random;
-public class KieAddressManager {
+import org.apache.servicecomb.http.client.common.AbstractAddressManager;
+import org.apache.servicecomb.http.client.event.RefreshEndpointEvent;
- private final Properties properties;
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
- private final List addresses;
+public class KieAddressManager extends AbstractAddressManager {
- private final Map configKey;
-
- private int index;
-
- public KieAddressManager(Properties properties, List addresses, Map configKey) {
- this.properties = properties;
- this.addresses = new ArrayList<>(addresses.size());
- this.configKey = configKey;
- addresses.forEach((address -> this.addresses.add(address)));
- this.index = new Random().nextInt(addresses.size());
- }
-
- public String nextAddress() {
- synchronized (this) {
- this.index++;
- if (this.index >= addresses.size()) {
- this.index = 0;
- }
- }
- return address();
- }
-
- public String address() {
- synchronized (this) {
- return addresses.get(index);
- }
- }
-
- public Properties getProperties() {
- return properties;
+ public KieAddressManager(List addresses, EventBus eventBus, String region, String availableZone) {
+ super(addresses, region, availableZone);
+ eventBus.register(this);
}
- public Map getConfigKey() {
- return configKey;
+ @Subscribe
+ public void onRefreshEndpointEvent(RefreshEndpointEvent event) {
+ refreshEndpoint(event, RefreshEndpointEvent.KIE_NAME);
}
}
diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KieConfiguration.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KieConfiguration.java
new file mode 100644
index 00000000000..9c75f2d09c2
--- /dev/null
+++ b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KieConfiguration.java
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.config.kie.client.model;
+
+public class KieConfiguration {
+ private boolean enableLongPolling;
+
+ private int pollingWaitInSeconds;
+
+ private int refreshIntervalInMillis = 15000;
+
+ private String project;
+
+ private String appName;
+
+ private String serviceName;
+
+ private String environment;
+
+ private String version;
+
+ private boolean enableAppConfig;
+
+ private boolean enableServiceConfig;
+
+ private boolean enableVersionConfig;
+
+ private boolean enableCustomConfig;
+
+ private String customLabelValue;
+
+ private String customLabel;
+
+ private boolean firstPullRequired;
+
+ public String getAppName() {
+ return appName;
+ }
+
+ public KieConfiguration setAppName(String appName) {
+ this.appName = appName;
+ return this;
+ }
+
+ public String getServiceName() {
+ return serviceName;
+ }
+
+ public KieConfiguration setServiceName(String serviceName) {
+ this.serviceName = serviceName;
+ return this;
+ }
+
+ public String getEnvironment() {
+ return environment;
+ }
+
+ public KieConfiguration setEnvironment(String environment) {
+ this.environment = environment;
+ return this;
+ }
+
+ public String getCustomLabelValue() {
+ return customLabelValue;
+ }
+
+ public KieConfiguration setCustomLabelValue(String customLabelValue) {
+ this.customLabelValue = customLabelValue;
+ return this;
+ }
+
+ public boolean isEnableAppConfig() {
+ return enableAppConfig;
+ }
+
+ public KieConfiguration setEnableAppConfig(boolean enableAppConfig) {
+ this.enableAppConfig = enableAppConfig;
+ return this;
+ }
+
+ public boolean isEnableServiceConfig() {
+ return enableServiceConfig;
+ }
+
+ public KieConfiguration setEnableServiceConfig(boolean enableServiceConfig) {
+ this.enableServiceConfig = enableServiceConfig;
+ return this;
+ }
+
+ public boolean isEnableCustomConfig() {
+ return enableCustomConfig;
+ }
+
+ public KieConfiguration setEnableCustomConfig(boolean enableCustomConfig) {
+ this.enableCustomConfig = enableCustomConfig;
+ return this;
+ }
+
+ public String getCustomLabel() {
+ return customLabel;
+ }
+
+ public KieConfiguration setCustomLabel(String customLabel) {
+ this.customLabel = customLabel;
+ return this;
+ }
+
+ public boolean isEnableLongPolling() {
+ return enableLongPolling;
+ }
+
+ public KieConfiguration setEnableLongPolling(boolean enableLongPolling) {
+ this.enableLongPolling = enableLongPolling;
+ return this;
+ }
+
+ public boolean isEnableVersionConfig() {
+ return enableVersionConfig;
+ }
+
+ public KieConfiguration setEnableVersionConfig(boolean enableVersionConfig) {
+ this.enableVersionConfig = enableVersionConfig;
+ return this;
+ }
+
+ public int getPollingWaitInSeconds() {
+ return pollingWaitInSeconds;
+ }
+
+ public KieConfiguration setPollingWaitInSeconds(int pollingWaitInSeconds) {
+ this.pollingWaitInSeconds = pollingWaitInSeconds;
+ return this;
+ }
+
+ public String getProject() {
+ return project;
+ }
+
+ public KieConfiguration setProject(String project) {
+ this.project = project;
+ return this;
+ }
+
+ public boolean isFirstPullRequired() {
+ return firstPullRequired;
+ }
+
+ public KieConfiguration setFirstPullRequired(boolean firstPullRequired) {
+ this.firstPullRequired = firstPullRequired;
+ return this;
+ }
+
+ public int getRefreshIntervalInMillis() {
+ return refreshIntervalInMillis;
+ }
+
+ public KieConfiguration setRefreshIntervalInMillis(int refreshIntervallnMillis) {
+ this.refreshIntervalInMillis = refreshIntervallnMillis;
+ return this;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public KieConfiguration setVersion(String version) {
+ this.version = version;
+ return this;
+ }
+}
diff --git a/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/LabelDocResponse.java b/clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/LabelDocResponse.java
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 7531afbe5b5..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
@@ -20,8 +20,10 @@
public enum ValueType {
yml,
yaml,
+ ini,
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 e8131103697..51d982e470c 100644
--- a/clients/http-client-common/pom.xml
+++ b/clients/http-client-common/pom.xml
@@ -22,7 +22,7 @@
clientsorg.apache.servicecomb
- 2.3.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/HttpTransportFactory.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpTransportFactory.java
index d9188ceb8a9..b1179321b3f 100644
--- a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpTransportFactory.java
+++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/HttpTransportFactory.java
@@ -28,6 +28,7 @@
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.servicecomb.foundation.ssl.SSLManager;
import org.apache.servicecomb.http.client.auth.RequestAuthHeaderProvider;
+import org.apache.servicecomb.http.client.common.HttpConfiguration.SSLProperties;
public class HttpTransportFactory {
// All parameters set to 5 seconds now.
@@ -44,8 +45,26 @@ public class HttpTransportFactory {
private HttpTransportFactory() {
}
+ public static HttpTransport createHttpTransport(HttpConfiguration.SSLProperties sslProperties,
+ RequestAuthHeaderProvider requestAuthHeaderProvider, HttpClientBuilder httpClientBuilder) {
+ PoolingHttpClientConnectionManager connectionManager = getPoolingHttpClientConnectionManager(sslProperties);
+ httpClientBuilder.setConnectionManager(connectionManager).disableCookieManagement();
+ return new HttpTransportImpl(httpClientBuilder.build(), requestAuthHeaderProvider);
+ }
+
public static HttpTransport createHttpTransport(HttpConfiguration.SSLProperties sslProperties,
RequestAuthHeaderProvider requestAuthHeaderProvider, RequestConfig config) {
+ PoolingHttpClientConnectionManager connectionManager = getPoolingHttpClientConnectionManager(sslProperties);
+
+ HttpClientBuilder httpClientBuilder = HttpClientBuilder.create().
+ setDefaultRequestConfig(config).
+ setConnectionManager(connectionManager).
+ disableCookieManagement();
+
+ return new HttpTransportImpl(httpClientBuilder.build(), requestAuthHeaderProvider);
+ }
+
+ private static PoolingHttpClientConnectionManager getPoolingHttpClientConnectionManager(SSLProperties sslProperties) {
//register http/https socket factory
RegistryBuilder builder = RegistryBuilder.create();
builder.register("http", PlainConnectionSocketFactory.INSTANCE);
@@ -62,13 +81,7 @@ public static HttpTransport createHttpTransport(HttpConfiguration.SSLProperties
connectionSocketFactoryRegistry);
connectionManager.setMaxTotal(MAX_TOTAL);
connectionManager.setDefaultMaxPerRoute(DEFAULT_MAX_PER_ROUTE);
-
- HttpClientBuilder httpClientBuilder = HttpClientBuilder.create().
- setDefaultRequestConfig(config).
- setConnectionManager(connectionManager).
- disableCookieManagement();
-
- return new HttpTransportImpl(httpClientBuilder.build(), requestAuthHeaderProvider);
+ return connectionManager;
}
public static HttpTransport createHttpTransport(HttpConfiguration.SSLProperties sslProperties,
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/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/OperationEvents.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/OperationEvents.java
new file mode 100644
index 00000000000..69896f750ec
--- /dev/null
+++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/OperationEvents.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.http.client.event;
+
+public abstract class OperationEvents {
+ public static class UnAuthorizedOperationEvent extends OperationEvents {
+ private final String address;
+
+ public UnAuthorizedOperationEvent(String address) {
+ this.address = address;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+ }
+}
diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/RefreshEndpointEvent.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/RefreshEndpointEvent.java
new file mode 100644
index 00000000000..4e4f1be648e
--- /dev/null
+++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/event/RefreshEndpointEvent.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.http.client.event;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class RefreshEndpointEvent {
+
+ public static final String SERVICE_CENTER_NAME = "SERVICECENTER";
+
+ public static final String KIE_NAME = "KIE";
+
+ public static final String CONFIG_CENTER_NAME = "CseConfigCenter";
+
+ public static final String CSE_MONITORING_NAME = "CseMonitoring";
+
+ private static final String SAME_ZONE = "sameZone";
+
+ private static final String SAME_REGION = "sameRegion";
+
+ private Map> zoneAndRegion = new HashMap<>();
+
+ private String name;
+
+ public RefreshEndpointEvent(Map> zoneAndRegion, String name) {
+ this.zoneAndRegion = zoneAndRegion;
+ this.name = name;
+ }
+
+ public List getSameZone() {
+ if (zoneAndRegion.get(SAME_ZONE).isEmpty()) {
+ return new ArrayList<>();
+ }
+ return zoneAndRegion.get(SAME_ZONE);
+ }
+
+ public List getSameRegion() {
+ if (zoneAndRegion.get(SAME_REGION).isEmpty()) {
+ return new ArrayList<>();
+ }
+ return zoneAndRegion.get(SAME_REGION);
+ }
+
+ public Map> getZoneAndRegion() {
+ return zoneAndRegion;
+ }
+
+ public void setZoneAndRegion(Map> zoneAndRegion) {
+ this.zoneAndRegion = zoneAndRegion;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/task/AbstractTask.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/task/AbstractTask.java
index e05eef2d5b4..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,22 +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;
}
@@ -46,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) {
@@ -58,14 +61,36 @@ public void execute() {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractTask.class);
- private final ExecutorService taskPool;
+ protected ExecutorService taskPool;
+
+ private volatile boolean running = true;
+
+ public static AtomicInteger taskCounter = new AtomicInteger(0);
+
+ private ScheduledExecutorService addrCheckExecutor;
protected AbstractTask(String taskName) {
+ initTaskPool(taskName);
+ Runtime.getRuntime().addShutdownHook(new Thread(AbstractTask.this::stop, taskName + "-shutdown-hook"));
+ }
+
+ protected void initTaskPool(String taskName) {
this.taskPool = Executors.newSingleThreadExecutor((task) ->
- new Thread(task, taskName));
+ new Thread(task, taskName + "-" + taskCounter.getAndIncrement()));
+ }
+
+ protected void schedulerCheckAddressAvailable(String taskName, Runnable task, long delayTime) {
+ if (addrCheckExecutor == null) {
+ addrCheckExecutor = Executors.newScheduledThreadPool(1, (t) -> new Thread(t, taskName));
+ }
+ addrCheckExecutor.scheduleWithFixedDelay(task, delayTime, delayTime, TimeUnit.MILLISECONDS);
}
protected void startTask(Task task) {
+ if (!running) {
+ return;
+ }
+
try {
this.taskPool.execute(() -> {
try {
@@ -80,6 +105,16 @@ protected void startTask(Task task) {
}
public void stop() {
- this.taskPool.shutdownNow();
+ try {
+ running = false;
+ this.taskPool.shutdown();
+ this.taskPool.awaitTermination(10, TimeUnit.SECONDS);
+ if (addrCheckExecutor != null) {
+ this.addrCheckExecutor.shutdown();
+ this.addrCheckExecutor.awaitTermination(10, TimeUnit.SECONDS);
+ }
+ } catch (InterruptedException e) {
+ LOGGER.warn("tasks not shutdown in time {}", e.getMessage());
+ }
}
}
diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/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 0315012af02..49f481934cc 100644
--- a/clients/pom.xml
+++ b/clients/pom.xml
@@ -23,7 +23,7 @@
org.apache.servicecombjava-chassis-parent
- 2.3.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 bb29daec41f..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/client/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 f6d13a5be70..ccc3900e9db 100755
--- a/clients/service-center-client/pom.xml
+++ b/clients/service-center-client/pom.xml
@@ -22,7 +22,7 @@
clientsorg.apache.servicecomb
- 2.3.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 107af8dff4f..00000000000
--- a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/AddressManager.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.servicecomb.service.center.client;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-
-import org.apache.servicecomb.http.client.common.HttpUtils;
-
-public class AddressManager {
- private final String projectName;
-
- private final List addresses;
-
- private int index;
-
- public AddressManager(String projectName, List addresses) {
- this.projectName = projectName;
- this.addresses = new ArrayList<>(addresses.size());
- addresses.forEach((address -> this.addresses.add(address)));
- this.index = new Random().nextInt(addresses.size());
- }
-
- private String formatAddress(String address) {
- try {
- return address + "/v4/" + HttpUtils.encodeURLParam(this.projectName);
- } catch (Exception e) {
- throw new IllegalStateException("not possible");
- }
- }
-
- public void changeAddress() {
- synchronized (this) {
- this.index++;
- if (this.index >= addresses.size()) {
- this.index = 0;
- }
- }
- }
-
- public boolean sslEnabled() {
- return address().startsWith("https://");
- }
-
- public String address() {
- synchronized (this) {
- 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 8db2565458d..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;
@@ -36,7 +37,9 @@
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;
@@ -53,31 +56,64 @@
import org.apache.servicecomb.service.center.client.model.RegisteredMicroserviceInstanceResponse;
import org.apache.servicecomb.service.center.client.model.RegisteredMicroserviceResponse;
import org.apache.servicecomb.service.center.client.model.SchemaInfo;
+import org.apache.servicecomb.service.center.client.model.UpdatePropertiesRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.core.env.Environment;
+
+import com.google.common.eventbus.EventBus;
public class ServiceCenterClient implements ServiceCenterOperation {
private static final Logger LOGGER = LoggerFactory.getLogger(ServiceCenterClient.class);
- private ServiceCenterRawClient httpClient;
+ private static final String CLIENT_CONNECT_TIMEOUT = "servicecomb.registry.sc.client.timeout.connect";
+
+ private static final String CLIENT_REQUEST_TIMEOUT = "servicecomb.registry.sc.client.timeout.request";
+
+ private static final String CLIENT_SOCKET_TIMEOUT = "servicecomb.registry.sc.client.timeout.socket";
+
+ private final ServiceCenterRawClient httpClient;
+
+ private final ServiceCenterAddressManager addressManager;
- public ServiceCenterClient(ServiceCenterRawClient httpClient) {
+ public ServiceCenterClient(ServiceCenterRawClient httpClient, ServiceCenterAddressManager addressManager) {
this.httpClient = httpClient;
+ this.addressManager = addressManager;
}
- public ServiceCenterClient(AddressManager addressManager,
+ public ServiceCenterClient setEventBus(EventBus eventBus) {
+ addressManager.setEventBus(eventBus);
+ this.httpClient.setEventBus(eventBus);
+ return this;
+ }
+
+ public ServiceCenterClient(ServiceCenterAddressManager addressManager,
SSLProperties sslProperties,
RequestAuthHeaderProvider requestAuthHeaderProvider,
String tenantName,
- Map extraGlobalHeaders) {
- 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
@@ -86,12 +122,11 @@ public MicroserviceInstancesResponse getServiceCenterInstances() {
HttpResponse response = httpClient.getHttpRequest("/registry/health", null, null);
if (response.getStatusCode() == HttpStatus.SC_OK) {
return HttpUtils.deserialize(response.getContent(), MicroserviceInstancesResponse.class);
- } else {
- throw new OperationException(
- "get service-center instances fails, statusCode = " + response.getStatusCode() + "; message = " + response
- .getMessage()
- + "; content = " + response.getContent());
}
+ throw new OperationException(
+ "get service-center instances fails, statusCode = " + response.getStatusCode() + "; message = " + response
+ .getMessage()
+ + "; content = " + response.getContent());
} catch (IOException e) {
throw new OperationException(
"get service-center instances fails", e);
@@ -107,12 +142,11 @@ public RegisteredMicroserviceResponse registerMicroservice(Microservice microser
.postHttpRequest("/registry/microservices", null, HttpUtils.serialize(request));
if (response.getStatusCode() == HttpStatus.SC_OK) {
return HttpUtils.deserialize(response.getContent(), RegisteredMicroserviceResponse.class);
- } else {
- throw new OperationException(
- "register service fails, statusCode = " + response.getStatusCode() + "; message = " + response
- .getMessage()
- + "; content = " + response.getContent());
}
+ throw new OperationException(
+ "register service fails, statusCode = " + response.getStatusCode() + "; message = " + response
+ .getMessage()
+ + "; content = " + response.getContent());
} catch (IOException e) {
throw new OperationException(
"register service fails", e);
@@ -125,12 +159,11 @@ public MicroservicesResponse getMicroserviceList() {
HttpResponse response = httpClient.getHttpRequest("/registry/microservices", null, null);
if (response.getStatusCode() == HttpStatus.SC_OK) {
return HttpUtils.deserialize(response.getContent(), MicroservicesResponse.class);
- } else {
- throw new OperationException(
- "get service List fails, statusCode = " + response.getStatusCode() + "; message = " + response
- .getMessage()
- + "; content = " + response.getContent());
}
+ throw new OperationException(
+ "get service List fails, statusCode = " + response.getStatusCode() + "; message = " + response
+ .getMessage()
+ + "; content = " + response.getContent());
} catch (IOException e) {
throw new OperationException(
"get service List fails", e);
@@ -150,12 +183,11 @@ public RegisteredMicroserviceResponse queryServiceId(Microservice microservice)
HttpResponse response = httpClient.getHttpRequest(uriBuilder.build().toString(), null, null);
if (response.getStatusCode() == HttpStatus.SC_OK) {
return HttpUtils.deserialize(response.getContent(), RegisteredMicroserviceResponse.class);
- } else {
- LOGGER.info("Query serviceId fails, statusCode = " + response.getStatusCode() + "; message = " + response
- .getMessage()
- + "; content = " + response.getContent());
- return null;
}
+ LOGGER.info("Query serviceId fails, statusCode = " + response.getStatusCode() + "; message = " + response
+ .getMessage()
+ + "; content = " + response.getContent());
+ return null;
} catch (IOException e) {
throw new OperationException(
"query serviceId fails", e);
@@ -173,12 +205,11 @@ public Microservice getMicroserviceByServiceId(String serviceId) {
MicroserviceResponse microserviceResponse = HttpUtils
.deserialize(response.getContent(), MicroserviceResponse.class);
return microserviceResponse.getService();
- } else {
- throw new OperationException(
- "get service message fails, statusCode = " + response.getStatusCode() + "; message = " + response
- .getMessage()
- + "; content = " + response.getContent());
}
+ throw new OperationException(
+ "get service message fails, statusCode = " + response.getStatusCode() + "; message = " + response
+ .getMessage()
+ + "; content = " + response.getContent());
} catch (IOException e) {
throw new OperationException(
"get service message fails", e);
@@ -195,12 +226,11 @@ public RegisteredMicroserviceInstanceResponse registerMicroserviceInstance(Micro
HttpUtils.serialize(request));
if (response.getStatusCode() == HttpStatus.SC_OK) {
return HttpUtils.deserialize(response.getContent(), RegisteredMicroserviceInstanceResponse.class);
- } else {
- throw new OperationException(
- "register service instance fails, statusCode = " + response.getStatusCode() + "; message = " + response
- .getMessage()
- + "; content = " + response.getContent());
}
+ throw new OperationException(
+ "register service instance fails, statusCode = " + response.getStatusCode() + "; message = " + response
+ .getMessage()
+ + "; content = " + response.getContent());
} catch (IOException e) {
throw new OperationException(
"register service instance fails", e);
@@ -227,15 +257,20 @@ public FindMicroserviceInstancesResponse findMicroserviceInstance(String consume
result.setMicroserviceInstancesResponse(
HttpUtils.deserialize(response.getContent(), MicroserviceInstancesResponse.class));
return result;
- } else if (response.getStatusCode() == HttpStatus.SC_NOT_MODIFIED) {
+ }
+ if (response.getStatusCode() == HttpStatus.SC_NOT_MODIFIED) {
result.setModified(false);
return result;
- } else {
- throw new OperationException(
- "get service instances list fails, statusCode = " + response.getStatusCode() + "; message = " + response
- .getMessage()
- + "; content = " + response.getContent());
}
+ if (response.getStatusCode() == HttpStatus.SC_TOO_MANY_REQUESTS) {
+ LOGGER.warn("rate limited, keep the local service {}#{} instance cache unchanged.", appId, serviceName);
+ result.setModified(false);
+ return result;
+ }
+ throw new OperationException(
+ "get service instances list fails, statusCode = " + response.getStatusCode() + "; message = " + response
+ .getMessage()
+ + "; content = " + response.getContent());
} catch (IOException e) {
throw new OperationException(
"get service instances list fails", e);
@@ -249,12 +284,11 @@ public MicroserviceInstancesResponse getMicroserviceInstanceList(String serviceI
.getHttpRequest("/registry/microservices/" + serviceId + "/instances", null, null);
if (response.getStatusCode() == HttpStatus.SC_OK) {
return HttpUtils.deserialize(response.getContent(), MicroserviceInstancesResponse.class);
- } else {
- throw new OperationException(
- "get service instances list fails, statusCode = " + response.getStatusCode() + "; message = " + response
- .getMessage()
- + "; content = " + response.getContent());
}
+ throw new OperationException(
+ "get service instances list fails, statusCode = " + response.getStatusCode() + "; message = " + response
+ .getMessage()
+ + "; content = " + response.getContent());
} catch (IOException e) {
throw new OperationException(
"get service instances list fails", e);
@@ -270,38 +304,30 @@ public MicroserviceInstance getMicroserviceInstance(String serviceId, String ins
MicroserviceInstanceResponse instanceResponse = HttpUtils
.deserialize(response.getContent(), MicroserviceInstanceResponse.class);
return instanceResponse.getInstance();
- } else {
- throw new OperationException(
- "get service instance message fails, statusCode = " + response.getStatusCode() + "; message = " + response
- .getMessage()
- + "; content = " + response.getContent());
}
+ throw new OperationException(
+ "get service instance message fails, statusCode = " + response.getStatusCode() + "; message = " + response
+ .getMessage()
+ + "; content = " + response.getContent());
} catch (IOException e) {
throw new OperationException(
"get service instance message fails", e);
}
}
- /**
- * Delete a microservice instance
- *
- * @param serviceId
- * @param instanceId
- * @return
- * @throws OperationException
- */
+ @Override
public void deleteMicroserviceInstance(String serviceId, String instanceId) {
try {
HttpResponse response = httpClient
.deleteHttpRequest("/registry/microservices/" + serviceId + "/instances/" + instanceId, null, null);
if (response.getStatusCode() == HttpStatus.SC_OK) {
LOGGER.info("Delete service instance successfully.");
- } else {
- throw new OperationException(
- "delete service instance fails, statusCode = " + response.getStatusCode() + "; message = " + response
- .getMessage()
- + "; content = " + response.getContent());
+ return;
}
+ throw new OperationException(
+ "delete service instance fails, statusCode = " + response.getStatusCode() + "; message = " + response
+ .getMessage()
+ + "; content = " + response.getContent());
} catch (IOException e) {
throw new OperationException(
"delete service instance fails", e);
@@ -315,39 +341,29 @@ public boolean updateMicroserviceInstanceStatus(String serviceId, String instanc
HttpResponse response = httpClient.putHttpRequest(
"/registry/microservices/" + serviceId + "/instances/" + instanceId + "/status?value=" + status, null, null);
if (response.getStatusCode() == HttpStatus.SC_OK) {
- LOGGER.info("UPDATE STATUS OK");
return true;
- } else {
- throw new OperationException(
- "update service instance status fails, statusCode = " + response.getStatusCode() + "; message = " + response
- .getMessage()
- + "; content = " + response.getContent());
}
+ throw new OperationException(
+ "update service instance status fails, statusCode = " + response.getStatusCode() + "; message = " + response
+ .getMessage()
+ + "; content = " + response.getContent());
} catch (IOException e) {
throw new OperationException(
"update service instance status fails", e);
}
}
- /**
- * Batch send heartbeats to service-center
- *
- * @param heartbeatsRequest
- * @return
- * @throws OperationException
- */
+ @Override
public void sendHeartBeats(HeartbeatsRequest heartbeatsRequest) {
try {
HttpResponse response = httpClient
.putHttpRequest("/registry/heartbeats", null, HttpUtils.serialize(heartbeatsRequest));
-
if (response.getStatusCode() == HttpStatus.SC_OK) {
- LOGGER.info("HEARTBEATS SUCCESS");
- } else {
- throw new OperationException(
- "heartbeats fails, statusCode = " + response.getStatusCode() + "; message = " + response.getMessage()
- + "; content = " + response.getContent());
+ return;
}
+ throw new OperationException(
+ "heartbeats fails, statusCode = " + response.getStatusCode() + "; message = " + response.getMessage()
+ + "; content = " + response.getContent());
} catch (IOException e) {
throw new OperationException(
"heartbeats fails ", e);
@@ -363,38 +379,35 @@ public boolean sendHeartBeat(String serviceId, String instanceId) {
if (response.getStatusCode() == HttpStatus.SC_OK) {
return true;
- } else {
- throw new OperationException(
- "heartbeats fails, statusCode = " + response.getStatusCode() + "; message = " + response.getMessage()
- + "; content = " + response.getContent());
}
+ throw new OperationException(
+ "heartbeats fails, statusCode = " + response.getStatusCode() + "; message = " + response.getMessage()
+ + "; content = " + response.getContent());
} catch (IOException e) {
throw new OperationException(
"heartbeats fails ", e);
}
}
- /**
- * Get schemas list of service
- *
- * @param serviceId
- * @return
- * @throws OperationException
- */
- public List getServiceSchemasList(String serviceId) {
+ @Override
+ public List getServiceSchemasList(String serviceId, boolean withContent) {
+ String url = "/registry/microservices/" + serviceId + "/schemas";
+ if (withContent) {
+ url = url + "?withSchema=1";
+ }
+
try {
HttpResponse response = httpClient
- .getHttpRequest("/registry/microservices/" + serviceId + "/schemas", null, null);
+ .getHttpRequest(url, null, null);
if (response.getStatusCode() == HttpStatus.SC_OK) {
GetSchemaListResponse getSchemaResponse = HttpUtils
.deserialize(response.getContent(), GetSchemaListResponse.class);
return getSchemaResponse.getSchemas();
- } else {
- throw new OperationException(
- "get service schemas list fails, statusCode = " + response.getStatusCode() + "; message = " + response
- .getMessage()
- + "; content = " + response.getContent());
}
+ throw new OperationException(
+ "get service schemas list fails, statusCode = " + response.getStatusCode() + "; message = " + response
+ .getMessage()
+ + "; content = " + response.getContent());
} catch (IOException e) {
throw new OperationException(
"get service schemas list fails", e);
@@ -416,12 +429,11 @@ public String getServiceSchemaContext(String serviceId, String schemaId) {
if (response.getStatusCode() == HttpStatus.SC_OK) {
GetSchemaResponse getSchemaResponse = HttpUtils.deserialize(response.getContent(), GetSchemaResponse.class);
return getSchemaResponse.getSchema();
- } else {
- throw new OperationException(
- "get service schema context fails, statusCode = " + response.getStatusCode() + "; message = " + response
- .getMessage()
- + "; content = " + response.getContent());
}
+ throw new OperationException(
+ "get service schema context fails, statusCode = " + response.getStatusCode() + "; message = " + response
+ .getMessage()
+ + "; content = " + response.getContent());
} catch (IOException e) {
throw new OperationException(
"get service schemas context fails", e);
@@ -436,12 +448,11 @@ public boolean registerSchema(String serviceId, String schemaId, CreateSchemaReq
HttpUtils.serialize(schema));
if (response.getStatusCode() == HttpStatus.SC_OK) {
return true;
- } else {
- throw new OperationException(
- "update service schema fails, statusCode = " + response.getStatusCode() + "; message = " + response
- .getMessage()
- + "; content = " + response.getContent());
}
+ throw new OperationException(
+ "update service schema fails, statusCode = " + response.getStatusCode() + "; message = " + response
+ .getMessage()
+ + "; content = " + response.getContent());
} catch (IOException e) {
throw new OperationException(
"update service schema fails", e);
@@ -459,12 +470,11 @@ public boolean updateServiceSchemaContext(String serviceId, SchemaInfo schemaInf
HttpUtils.serialize(request));
if (response.getStatusCode() == HttpStatus.SC_OK) {
return true;
- } else {
- throw new OperationException(
- "update service schema fails, statusCode = " + response.getStatusCode() + "; message = " + response
- .getMessage()
- + "; content = " + response.getContent());
}
+ throw new OperationException(
+ "update service schema fails, statusCode = " + response.getStatusCode() + "; message = " + response
+ .getMessage()
+ + "; content = " + response.getContent());
} catch (IOException e) {
throw new OperationException(
"update service schema fails", e);
@@ -478,14 +488,12 @@ public boolean batchUpdateServiceSchemaContext(String serviceId, ModifySchemasRe
.postHttpRequest("/registry/microservices/" + serviceId + "/schemas", null,
HttpUtils.serialize(modifySchemasRequest));
if (response.getStatusCode() == HttpStatus.SC_OK) {
- LOGGER.info("UPDATE SCHEMA OK");
return true;
- } else {
- throw new OperationException(
- "update service schema fails, statusCode = " + response.getStatusCode() + "; message = " + response
- .getMessage()
- + "; content = " + response.getContent());
}
+ throw new OperationException(
+ "update service schema fails, statusCode = " + response.getStatusCode() + "; message = " + response
+ .getMessage()
+ + "; content = " + response.getContent());
} catch (IOException e) {
throw new OperationException(
"update service schema fails", e);
@@ -493,29 +501,69 @@ public boolean batchUpdateServiceSchemaContext(String serviceId, ModifySchemasRe
}
@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);
return result;
- } else if (response.getStatusCode() == HttpStatus.SC_NOT_FOUND ||
+ }
+ if (response.getStatusCode() == HttpStatus.SC_NOT_FOUND) {
+ RbacTokenResponse result = new RbacTokenResponse();
+ result.setStatusCode(response.getStatusCode());
+ return result;
+ }
+ if (response.getStatusCode() == HttpStatus.SC_UNAUTHORIZED ||
response.getStatusCode() == HttpStatus.SC_FORBIDDEN) {
RbacTokenResponse result = new RbacTokenResponse();
result.setStatusCode(response.getStatusCode());
+ ErrorMessage errorMessage = HttpUtils.deserialize(response.getContent(), ErrorMessage.class);
+ result.setErrorCode(errorMessage.getErrorCode());
return result;
- } else {
- throw new OperationException(
- "query token failed, statusCode = " + response.getStatusCode() + "; message = " + response
- .getMessage()
- + "; content = " + response.getContent());
}
+ throw new OperationException(
+ "query token failed, statusCode = " + response.getStatusCode() + "; message = " + response
+ .getMessage()
+ + "; content = " + response.getContent());
} catch (IOException e) {
throw new OperationException(
"query token failed", e);
}
}
+
+ @Override
+ public boolean updateMicroserviceProperties(String serviceId, Map serviceProperties,
+ Framework framework) {
+ try {
+ UpdatePropertiesRequest request = new UpdatePropertiesRequest();
+ request.setProperties(serviceProperties);
+ request.setFramework(framework);
+ HttpResponse response = httpClient.putHttpRequest(
+ "/registry/microservices/" + serviceId + "/properties", null, HttpUtils.serialize(request));
+ if (response.getStatusCode() == HttpStatus.SC_OK) {
+ return true;
+ }
+ throw new OperationException(
+ "update service properties fails, statusCode = " + response.getStatusCode() + "; message = " + response
+ .getMessage()
+ + "; content = " + response.getContent());
+ } catch (IOException e) {
+ throw new OperationException(
+ "update service properties fails", e);
+ }
+ }
+
+ @Override
+ public void checkIsolationAddressAvailable() {
+ List isolationAddresses = addressManager.getIsolationAddresses();
+ if (isolationAddresses.isEmpty()) {
+ return;
+ }
+ for (String address : isolationAddresses) {
+ httpClient.checkAddressAvailable(address);
+ }
+ }
}
diff --git a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterConfiguration.java b/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterConfiguration.java
deleted file mode 100644
index 794b97655e3..00000000000
--- a/clients/service-center-client/src/main/java/org/apache/servicecomb/service/center/client/ServiceCenterConfiguration.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.servicecomb.service.center.client;
-
-public interface ServiceCenterConfiguration {
- class AddressProperties {
- private boolean address;
-
- public boolean isAddress() {
- return address;
- }
-
- public void setAddress(boolean address) {
- this.address = 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 1b630352b54..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
@@ -17,9 +17,12 @@
package org.apache.servicecomb.service.center.client;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.servicecomb.http.client.task.AbstractTask;
@@ -27,6 +30,7 @@
import org.apache.servicecomb.service.center.client.DiscoveryEvents.InstanceChangedEvent;
import org.apache.servicecomb.service.center.client.DiscoveryEvents.PullInstanceEvent;
import org.apache.servicecomb.service.center.client.model.FindMicroserviceInstancesResponse;
+import org.apache.servicecomb.service.center.client.model.Microservice;
import org.apache.servicecomb.service.center.client.model.MicroserviceInstance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -35,11 +39,14 @@
import com.google.common.eventbus.Subscribe;
public class ServiceCenterDiscovery extends AbstractTask {
- private static final String ALL_VERSION = "0+";
- private static final long POLL_INTERVAL = 15000;
+ public static final int MAX_INTERVAL = 600000;
- private boolean started = false;
+ public static final int MIN_INTERVAL = 1000;
+
+ private static final String ALL_VERSION = "0+";
+
+ private static volatile boolean pullInstanceTaskOnceInProgress = false;
public static class SubscriptionKey {
final String appId;
@@ -76,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;
@@ -86,6 +93,16 @@ public static class SubscriptionValue {
private final Map instancesCache = new ConcurrentHashMap<>();
+ private final Map microserviceCache = new ConcurrentHashMap<>();
+
+ private long pollInterval = 15000;
+
+ private boolean started = false;
+
+ private final Object lock = new Object();
+
+ private final Random random = new Random();
+
public ServiceCenterDiscovery(ServiceCenterClient serviceCenterClient, EventBus eventBus) {
super("service-center-discovery-task");
this.serviceCenterClient = serviceCenterClient;
@@ -93,6 +110,14 @@ public ServiceCenterDiscovery(ServiceCenterClient serviceCenterClient, EventBus
this.eventBus.register(this);
}
+ public ServiceCenterDiscovery setPollInterval(long interval) {
+ if (interval > MAX_INTERVAL || interval < MIN_INTERVAL) {
+ return this;
+ }
+ this.pollInterval = interval;
+ return this;
+ }
+
public void updateMyselfServiceId(String myselfServiceId) {
this.myselfServiceId = myselfServiceId;
}
@@ -104,64 +129,121 @@ public void startDiscovery() {
}
}
- public void register(SubscriptionKey subscriptionKey) {
- this.instancesCache.computeIfAbsent(subscriptionKey, (key) -> new SubscriptionValue());
- pullInstance(subscriptionKey, this.instancesCache.get(subscriptionKey));
+ public void registerIfNotPresent(SubscriptionKey subscriptionKey) {
+ if (this.instancesCache.get(subscriptionKey) == null) {
+ synchronized (lock) {
+ if (this.instancesCache.get(subscriptionKey) == null) {
+ SubscriptionValue value = new SubscriptionValue();
+ pullInstance(subscriptionKey, value, false);
+ this.instancesCache.put(subscriptionKey, value);
+ }
+ }
+ }
}
public List getInstanceCache(SubscriptionKey key) {
return this.instancesCache.get(key).instancesCache;
}
- public boolean isRegistered(SubscriptionKey key) {
- return this.instancesCache.get(key) != null;
- }
-
@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);
if (instancesResponse.isModified()) {
- // java chassis 实现了空实例保护,这里暂时不实现。
- LOGGER.info("Instance changed event, "
- + "current: revision={}, instances={}; "
- + "origin: revision={}, instances={}; "
- + "appId={}, serviceName={}",
+ List instances = instancesResponse.getMicroserviceInstancesResponse().getInstances()
+ == null ? Collections.emptyList() : instancesResponse.getMicroserviceInstancesResponse().getInstances();
+ setMicroserviceInfo(instances);
+ LOGGER.info("Instance changed event. "
+ + "Current: revision={}, instances={}. "
+ + "Origin: revision={}, instances={}. "
+ + "appId={}, serviceName={}.",
instancesResponse.getRevision(),
- instanceToString(instancesResponse.getMicroserviceInstancesResponse().getInstances()),
+ instanceToString(instances),
v.revision,
instanceToString(v.instancesCache),
k.appId,
k.serviceName
);
- v.instancesCache = instancesResponse.getMicroserviceInstancesResponse().getInstances();
+ 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.", e);
+ LOGGER.warn("find service {}#{} instance failed, remaining local instances cache [{}], cause message: {}",
+ k.appId, k.serviceName, instanceToString(v.instancesCache), e.getMessage());
}
}
+ private void setMicroserviceInfo(List instances) {
+ instances.forEach(instance -> {
+ Microservice microservice = microserviceCache
+ .computeIfAbsent(instance.getServiceId(), id -> {
+ try {
+ return serviceCenterClient.getMicroserviceByServiceId(id);
+ } catch (Exception e) {
+ LOGGER.error("Find microservice by id={} failed", id, e);
+ throw e;
+ }
+ });
+ instance.setMicroservice(microservice);
+ });
+ }
+
class PullInstanceTask implements Task {
@Override
public void execute() {
pullAllInstance();
- startTask(new BackOffSleepTask(POLL_INTERVAL, 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);
+ }
});
+ emptyInstancesCache.forEach(instancesCache::remove);
+ emptyInstancesCache.clear();
}
private static String instanceToString(List instances) {
@@ -175,8 +257,9 @@ private static String instanceToString(List instances) {
sb.append(endpoint.length() > 64 ? endpoint.substring(0, 64) : endpoint);
sb.append("|");
}
+ 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 41c25986c60..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
@@ -17,9 +17,14 @@
package org.apache.servicecomb.service.center.client;
+import java.util.List;
+import java.util.Map;
+
import org.apache.servicecomb.service.center.client.exception.OperationException;
import org.apache.servicecomb.service.center.client.model.CreateSchemaRequest;
import org.apache.servicecomb.service.center.client.model.FindMicroserviceInstancesResponse;
+import org.apache.servicecomb.service.center.client.model.Framework;
+import org.apache.servicecomb.service.center.client.model.HeartbeatsRequest;
import org.apache.servicecomb.service.center.client.model.Microservice;
import org.apache.servicecomb.service.center.client.model.MicroserviceInstance;
import org.apache.servicecomb.service.center.client.model.MicroserviceInstanceStatus;
@@ -112,6 +117,13 @@ FindMicroserviceInstancesResponse findMicroserviceInstance(String consumerId, St
String versionRule,
String revision);
+ /**
+ * Delete a microservice instance
+ *
+ * @throws OperationException
+ */
+ void deleteMicroserviceInstance(String serviceId, String instanceId);
+
/**
* Update status of microservice Instance
*
@@ -144,6 +156,14 @@ boolean updateMicroserviceInstanceStatus(String serviceId, String instanceId,
*/
boolean batchUpdateServiceSchemaContext(String serviceId, ModifySchemasRequest modifySchemasRequest);
+ /**
+ * Batch send heartbeats to service-center
+ *
+ * @param heartbeatsRequest
+ * @throws OperationException
+ */
+ void sendHeartBeats(HeartbeatsRequest heartbeatsRequest);
+
/**
* send heart beat of this instance.
* @return if heartbeat is successful
@@ -151,11 +171,32 @@ boolean updateMicroserviceInstanceStatus(String serviceId, String instanceId,
*/
boolean sendHeartBeat(String serviceId, String instanceId);
+ /**
+ * Get schemas list of service
+ *
+ * @throws OperationException
+ */
+ List getServiceSchemasList(String serviceId, boolean withContent);
+
/**
* query token using user confidential
*
* @return if heartbeat is successful
* @throws OperationException If some problems happened to contact service center or non http 200 returned.
*/
- RbacTokenResponse queryToken(RbacTokenRequest request);
+ 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 303dfdae25b..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,86 +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