Merge pull request #8902 from alibaba/develop

Upgrade 2.1.1
This commit is contained in:
杨翊 SionYang 2022-08-08 18:12:15 +08:00 committed by GitHub
commit 41859be6a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
438 changed files with 9827 additions and 2698 deletions

View File

@ -21,7 +21,7 @@ A clear and concise description of what the bug is.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Acutally behavior**
**Actually behavior**
A clear and concise description of what you actually to happen.
**How to Reproduce**
@ -29,7 +29,7 @@ Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
4. See errors
**Desktop (please complete the following information):**
- OS: [e.g. Centos]

View File

@ -34,4 +34,8 @@ jobs:
- name: Build with Maven
run: mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U
- name: Test With Maven
run: mvn -Prelease-nacos clean test -DforkCount=0
run: mvn -Prelease-nacos clean test -DtrimStackTrace=false
- name: Codecov
uses: codecov/codecov-action@v3.1.0
with:
files: ./address/target/site/jacoco/jacoco.xml,./api/target/site/jacoco/jacoco.xml,./auth/target/site/jacoco/jacoco.xml,./client/target/site/jacoco/jacoco.xml,./common/target/site/jacoco/jacoco.xml,./consistency/target/site/jacoco/jacoco.xml,./console/target/site/jacoco/jacoco.xml,./core/target/site/jacoco/jacoco.xml,./naming/target/site/jacoco/jacoco.xml,./plugin-default-impl/target/site/jacoco/jacoco.xml,./plugin/auth/target/site/jacoco/jacoco.xml,./plugin/encryption/target/site/jacoco/jacoco.xml,./sys/target/site/jacoco/jacoco.xml

View File

@ -17,42 +17,42 @@ Nacos welcome new participants of any role, including user, contributor, committ
![](http://acm-public.oss-cn-hangzhou.aliyuncs.com/contributor_definition.png)
We encourage new comers actively join in Nacos projects and involving from user role to committer role, and even PMC role. In order to accomplish this, new comers needs to actively contribute in Nacos project. The following paragraph introduce how to contribute in Nacos way.
We encourage newcomers actively joining in Nacos projects and involving from user roles to committer roles, and even PMC roles. In order to accomplish this, new comers needs to actively contribute in Nacos project. The following paragraph introduce how to contribute in Nacos way.
#### Open / pickup an issue for preparation
If you find a typo in document, find a bug in code, or want new features, or want to give suggestions, you can [open an issue on GitHub](https://github.com/alibaba/Nacos/issues/new) to report it.
If you find a typo in a document, find a bug in code or want new features, or want to give suggestions, you can [open an issue on GitHub](https://github.com/alibaba/Nacos/issues/new) to report it.
If you just want to contribute directly you can choose the issue below.
- [Contribution Welcome](https://github.com/alibaba/nacos/labels/contribution%20welcome): Heavily needed issue, but currently short of hand.
- [good first issue](https://github.com/alibaba/nacos/labels/good%20first%20issue): Good for newcomers, new comer can pickup one for warm-up.
- [good first issue](https://github.com/alibaba/nacos/labels/good%20first%20issue): Good for newcomers, newcomers can pick up one for warm-up.
We strongly value documentation and integration with other projects such as Spring Cloud, Kubernetes, Dubbo, etc. We are very glad to work on any issue for these aspects.
Please note that any PR must be associated with a valid issue. Otherwise the PR will be rejected.
Please note that any PR must be associated with a valid issue. Otherwise, the PR will be rejected.
#### Begin your contribute
#### Begin your contribution
Now if you want to contribute, please create a new pull request.
We use the `develop` branch as the development branch, which indicates that this is a unstable branch.
We use the `develop` branch as the development branch, which indicates that this is an unstable branch.
Further more, our branching model complies to [https://nvie.com/posts/a-successful-git-branching-model/](https://nvie.com/posts/a-successful-git-branching-model/). We strongly suggest new comers walk through the above article before creating PR.
Furthermore, our branching model complies with [https://nvie.com/posts/a-successful-git-branching-model/](https://nvie.com/posts/a-successful-git-branching-model/). We strongly suggest new comers walk through the above article before creating PR.
Now, if you are ready to create PR, here is the workflow for contributors:
1. Fork to your own
2. Clone fork to local repository
2. Clone fork to a local repository
3. Create a new branch and work on it
4. Keep your branch in sync
5. Commit your changes (make sure your commit message concise)
5. Commit your changes (make sure your commit message is concise)
6. Push your commits to your forked repository
@ -73,7 +73,7 @@ When creating pull request:
6. After creating a PR, one or more reviewers will be assigned to the pull request.
7. Before merging a PR, squash any fix review feedback, typo, merged, and rebased sorts of commits. The final commit message should be clear and concise.
7. Before merging a PR, squash any fix review feedback, typo, merged and rebased sorts of commits. The final commit message should be clear and concise.
If your PR contains large changes, e.g. component refactor or new components, please write detailed documents about its design and usage.
@ -86,7 +86,7 @@ Some principles:
- Readability - Important code should be well-documented. API should have Javadoc. Code style should be complied with the existing one.
- Elegance: New functions, classes or components should be well designed.
- Elegance: New functions, classes or components should be well-designed.
- Testability - 80% of the new code should be covered by unit test cases.
@ -106,7 +106,7 @@ Generally speaking, contribute 8 non-trivial patches and get at least three diff
- ability to write good code (last but certainly not least)
A current committer nominates you by slacking the team on the Nacos issue with label "nomination"
A current committer nominates you by slacking the team on the Nacos issue with the label "nomination"
- your first and last name
@ -114,10 +114,10 @@ A current committer nominates you by slacking the team on the Nacos issue with l
- an explanation of why you should be a committer,
- Elaborate the top 3 PR and the associated issues the nominator has worked with you that can demonstrate your ability.
- Elaborate on the top 3 PR and the associated issues the nominator has worked with you that can demonstrate your ability.
Two other committer need to second your nomination. If no one objects in 5 working days (China), you're a committer. If anyone objects or wants more information, the committers discuss and usually come to a consensus (within the 5 working days). If issues cannot be resolved, there's a vote among current committers.
Two other committers need to second your nomination. If no one objects in 5 working days (China), you're a committer. If anyone objects or wants more information, the committers discuss and usually come to a consensus (within the 5 working days). If issues cannot be resolved, there's a vote among current committers.
![](http://acm-public.oss-cn-hangzhou.aliyuncs.com/nomination_process.png)

View File

@ -1,14 +1,14 @@
# How to Reporting bugs
# How to report bugs
If any part of the Nacos project has bugs or documentation mistakes, please let us know by [opening an issue][Nacos-issue]. We treat bugs and mistakes very seriously and believe no issue is too small, anyOne is implement. Before creating a bug report, please check that an issue reporting the same problem does not already exist.
To make the bug report accurate and easy to understand, please try to create bug reports that are:
- Specific. Include as much details as possible: which version, what environment, what configuration, etc. If the bug is related to running the Nacos server, please attach the Nacos log (the starting log with Nacos configuration is especially important).
- Specific. Include as many details as possible: which version, what environment, what configuration, etc. If the bug is related to running the Nacos server, please attach the Nacos log (the starting log with Nacos configuration is especially important).
- Reproducible. Include the steps to reproduce the problem. We understand some issues might be hard to reproduce, please includes the steps that might lead to the problem. If possible, please attach the affected Nacos data dir and stack strace to the bug report.
- Unique. Do not duplicate existing bug report.
- Unique. Do not duplicate the existing bug report.
It may be worthwhile to read [Elika Etemads article on filing good bug reports][filing-good-bugs] before creating a bug report.

View File

@ -46,6 +46,11 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>

View File

@ -0,0 +1,37 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.address.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
/**
* nacos web security configuration.
* @author onewe
*/
@Configuration
@Order(99)
public class AddressServerSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(requestMatcherRegistry -> requestMatcherRegistry.mvcMatchers("/nacos/v1/as/**").authenticated())
.csrf().disable().httpBasic();
}
}

View File

@ -28,7 +28,6 @@ import com.alibaba.nacos.naming.core.Instance;
import com.alibaba.nacos.naming.core.Service;
import com.alibaba.nacos.naming.core.ServiceManager;
import com.alibaba.nacos.common.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
@ -48,14 +47,19 @@ import java.util.List;
@RequestMapping({AddressServerConstants.ADDRESS_SERVER_REQUEST_URL + "/nodes"})
public class AddressServerClusterController {
@Autowired
private ServiceManager serviceManager;
private final ServiceManager serviceManager;
@Autowired
private AddressServerManager addressServerManager;
private final AddressServerManager addressServerManager;
private final AddressServerGeneratorManager addressServerGeneratorManager;
public AddressServerClusterController(ServiceManager serviceManager, AddressServerManager addressServerManager,
AddressServerGeneratorManager addressServerGeneratorManager) {
this.serviceManager = serviceManager;
this.addressServerManager = addressServerManager;
this.addressServerGeneratorManager = addressServerGeneratorManager;
}
@Autowired
private AddressServerGeneratorManager addressServerGeneratorManager;
/**
* Create new cluster.
@ -146,7 +150,7 @@ public class AddressServerClusterController {
List<Instance> instanceList = addressServerGeneratorManager
.generateInstancesByIps(serviceName, rawProductName, clusterName, ipArray);
serviceManager.removeInstance(Constants.DEFAULT_NAMESPACE_ID, serviceName, false,
instanceList.toArray(new Instance[instanceList.size()]));
instanceList.toArray(new Instance[0]));
} else {
responseEntity = ResponseEntity.status(HttpStatus.BAD_REQUEST).body(checkResult);
}

View File

@ -21,7 +21,6 @@ import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.naming.core.Cluster;
import com.alibaba.nacos.naming.core.Service;
import com.alibaba.nacos.naming.core.ServiceManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
@ -38,11 +37,15 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
public class ServerListController {
@Autowired
private ServiceManager serviceManager;
private final ServiceManager serviceManager;
@Autowired
private AddressServerGeneratorManager addressServerBuilderManager;
private final AddressServerGeneratorManager addressServerBuilderManager;
public ServerListController(ServiceManager serviceManager,
AddressServerGeneratorManager addressServerBuilderManager) {
this.serviceManager = serviceManager;
this.addressServerBuilderManager = addressServerBuilderManager;
}
/**
* Get cluster.

View File

@ -16,167 +16,233 @@
package com.alibaba.nacos.address;
import com.alibaba.nacos.common.codec.Base64;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.LinkedMultiValueMap;
import java.util.HashMap;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, properties = {
"spring.security.user.password=123456", "spring.security.user.name=user"})
public class AddressServerControllerTests {
private static final String PRODUCT_NACOS = "nacos";
private static final String PRODUCT_CONFIG = "config";
private static final String PRODUCT_NAMING = "naming";
private static final String DEFAULT_URL_CLUSTER = "serverlist";
private static final String HTTP_BASIC_INFO = getHttpBasicInfo();
private static final String GET_SERVERLIST_URL_FORMART = "http://127.0.0.1:8080/%s/%s";
@Autowired
private TestRestTemplate restTemplate;
//-----------------product=nacos,cluster=DEFAULT -------------------//
@BeforeClass
public static void before() {
System.setProperty("nacos.standalone", "true");
System.setProperty("embeddedStorage", "true");
}
@AfterClass
public static void teardown() {
System.clearProperty("nacos.standalone");
System.clearProperty("embeddedStorage");
}
private static String getHttpBasicInfo() {
String userName = "user";
String password = "123456";
String info = userName + ":" + password;
final byte[] bytes = Base64.encodeBase64(info.getBytes(StandardCharsets.UTF_8));
return "Basic " + new String(bytes, StandardCharsets.UTF_8);
}
@Test
public void postCluster() {
public void postClusterWithoutLogin() {
String ips = "127.0.0.100,127.0.0.102,127.0.0.104";
HashMap<String, String> params = new HashMap<>();
params.put("ips", ips);
String response = SimpleHttpTestUtils.doPost("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
System.err.println(response);
}
@Test
public void getCluster() {
LinkedMultiValueMap<String, String> params = new LinkedMultiValueMap<>(1);
params.add("ips", ips);
String getUrl = String.format(GET_SERVERLIST_URL_FORMART, PRODUCT_NACOS, DEFAULT_URL_CLUSTER);
String response = SimpleHttpTestUtils.doGet(getUrl, new HashMap<>(), "UTF-8");
System.err.println(response);
}
@Test
public void deleteCluster() {
HashMap<String, String> deleteIp = new HashMap<>();
deleteIp.put("ips", "127.0.0.104");
String response = SimpleHttpTestUtils.doDelete("http://127.0.0.1:8080/nacos/v1/as/nodes", deleteIp, "UTF-8");
System.err.println(response);
}
@Test
public void deleteClusterWithSpecIp() {
HashMap<String, String> params = new HashMap<>();
params.put("ips", "127.0.0.103");
String response = SimpleHttpTestUtils.doDelete("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
System.err.println(response);
}
@Test
public void putCluster() {
final ResponseEntity<String> postClusterResponseEntity = restTemplate.exchange(
RequestEntity.post("/nacos/v1/as/nodes").body(params), String.class);
String ips = "127.0.0.114";
HashMap<String, String> params = new HashMap<>();
params.put("ips", ips);
String response = SimpleHttpTestUtils.doPut("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
System.err.println(response);
Assert.assertEquals(postClusterResponseEntity.getStatusCode(), HttpStatus.UNAUTHORIZED);
}
//-----------------product=config,cluster=cluster01 -------------------//
@Test
public void postCluster() throws InterruptedException {
String ips = "127.0.0.100,127.0.0.102,127.0.0.104";
LinkedMultiValueMap<String, String> params = new LinkedMultiValueMap<>(1);
params.add("ips", ips);
final ResponseEntity<String> postClusterResponseEntity = restTemplate.exchange(
RequestEntity.post("/nacos/v1/as/nodes").header(HttpHeaders.AUTHORIZATION, HTTP_BASIC_INFO)
.body(params), String.class);
Assert.assertNotNull(postClusterResponseEntity);
Assert.assertEquals(HttpStatus.OK.value(), postClusterResponseEntity.getStatusCodeValue());
TimeUnit.MILLISECONDS.sleep(500L);
final ResponseEntity<String> getClusterResponseEntity = restTemplate.exchange(
RequestEntity.get("/nacos/serverlist").build(), String.class);
Assert.assertNotNull(getClusterResponseEntity);
Assert.assertEquals(HttpStatus.OK.value(), getClusterResponseEntity.getStatusCodeValue());
}
@Test
public void postClusterWithProduct() {
public void deleteClusterWithoutLogin() {
LinkedMultiValueMap<String, String> params = new LinkedMultiValueMap<>(1);
params.add("ips", "127.0.0.104");
final ResponseEntity<String> postClusterResponseEntity = restTemplate.exchange(
RequestEntity.post("/nacos/v1/as/nodes").body(params), String.class);
Assert.assertEquals(postClusterResponseEntity.getStatusCode(), HttpStatus.UNAUTHORIZED);
}
@Test
public void deleteCluster() throws InterruptedException {
LinkedMultiValueMap<String, String> params = new LinkedMultiValueMap<>(1);
params.add("ips", "127.0.0.104");
final ResponseEntity<String> postClusterResponseEntity = restTemplate.exchange(
RequestEntity.post("/nacos/v1/as/nodes").header(HttpHeaders.AUTHORIZATION, HTTP_BASIC_INFO)
.body(params), String.class);
Assert.assertNotNull(postClusterResponseEntity);
Assert.assertEquals(HttpStatus.OK.value(), postClusterResponseEntity.getStatusCodeValue());
TimeUnit.MILLISECONDS.sleep(500L);
final ResponseEntity<String> deleteClusterResponseEntity = restTemplate.exchange(
RequestEntity.delete("/nacos/v1/as/nodes?ips={ips}", "127.0.0.104")
.header(HttpHeaders.AUTHORIZATION, HTTP_BASIC_INFO).build(), String.class);
Assert.assertNotNull(deleteClusterResponseEntity);
Assert.assertEquals(HttpStatus.OK.value(), deleteClusterResponseEntity.getStatusCodeValue());
}
@Test
public void postClusterWithProduct() throws InterruptedException {
LinkedMultiValueMap<String, String> params = new LinkedMultiValueMap<>(2);
String ips = "127.0.0.101,127.0.0.102,127.0.0.103";
HashMap<String, String> params = new HashMap<>();
params.put("ips", ips);
params.put("product", PRODUCT_CONFIG);
String response = SimpleHttpTestUtils.doPost("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
System.err.println(response);
}
@Test
public void getClusterWithProduct() {
HashMap<String, String> params = new HashMap<>();
String getUrl = String.format(GET_SERVERLIST_URL_FORMART, PRODUCT_CONFIG, DEFAULT_URL_CLUSTER);
String response = SimpleHttpTestUtils.doGet(getUrl, params, "UTF-8");
System.err.println(response);
}
@Test
public void deleteClusterWithProduct() {
HashMap<String, String> params = new HashMap<>();
params.put("product", PRODUCT_CONFIG);
String response = SimpleHttpTestUtils.doDelete("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
System.err.println(response);
}
@Test
public void deleteClusterWithProductAndIp() {
HashMap<String, String> params = new HashMap<>();
params.put("product", PRODUCT_CONFIG);
params.put("ips", "127.0.0.196");
String response = SimpleHttpTestUtils.doDelete("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
System.err.println(response);
}
@Test
public void putClusterWithProduct() {
params.add("ips", ips);
params.add("product", PRODUCT_CONFIG);
String ips = "127.0.0.196";
HashMap<String, String> params = new HashMap<>();
params.put("ips", ips);
params.put("product", PRODUCT_CONFIG);
String response = SimpleHttpTestUtils.doPut("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
System.err.println(response);
final ResponseEntity<String> postClusterResponseEntity = restTemplate.exchange(
RequestEntity.post("/nacos/v1/as/nodes").header(HttpHeaders.AUTHORIZATION, HTTP_BASIC_INFO)
.body(params), String.class);
Assert.assertNotNull(postClusterResponseEntity);
Assert.assertEquals(HttpStatus.OK.value(), postClusterResponseEntity.getStatusCodeValue());
TimeUnit.MILLISECONDS.sleep(500L);
final ResponseEntity<String> getClusterResponseEntity = restTemplate.exchange(
RequestEntity.get("/{product}/serverlist", PRODUCT_CONFIG).build(), String.class);
Assert.assertNotNull(getClusterResponseEntity);
Assert.assertEquals(HttpStatus.OK.value(), getClusterResponseEntity.getStatusCodeValue());
final String body = getClusterResponseEntity.getBody();
Assert.assertNotNull(body);
}
//-----------------product=naming,cluster=cluster01 -------------------//
@Test
public void deleteClusterWithProduct() throws InterruptedException {
LinkedMultiValueMap<String, String> params = new LinkedMultiValueMap<>(1);
params.add("ips", "127.0.0.104");
params.add("product", PRODUCT_CONFIG);
final ResponseEntity<String> postClusterResponseEntity = restTemplate.exchange(
RequestEntity.post("/nacos/v1/as/nodes").header(HttpHeaders.AUTHORIZATION, HTTP_BASIC_INFO)
.body(params), String.class);
Assert.assertNotNull(postClusterResponseEntity);
Assert.assertEquals(HttpStatus.OK.value(), postClusterResponseEntity.getStatusCodeValue());
TimeUnit.MILLISECONDS.sleep(500L);
final ResponseEntity<String> deleteClusterResponseEntity = restTemplate.exchange(
RequestEntity.delete("/nacos/v1/as/nodes?product={product}&ips={ips}", PRODUCT_CONFIG, "127.0.0.104")
.header(HttpHeaders.AUTHORIZATION, HTTP_BASIC_INFO).build(), String.class);
Assert.assertNotNull(deleteClusterResponseEntity);
Assert.assertEquals(HttpStatus.OK.value(), deleteClusterResponseEntity.getStatusCodeValue());
}
@Test
public void postClusterWithProductAndCluster() {
public void postClusterWithProductAndCluster() throws InterruptedException {
LinkedMultiValueMap<String, String> params = new LinkedMultiValueMap<>(1);
String ips = "127.0.0.100,127.0.0.200,127.0.0.31";
HashMap<String, String> params = new HashMap<>();
params.put("ips", ips);
params.put("product", PRODUCT_NAMING);
params.put("cluster", "cluster01");
String response = SimpleHttpTestUtils.doPost("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
System.err.println(response);
}
@Test
public void getClusterWithProductAndCluster() {
HashMap<String, String> params = new HashMap<>();
String getUrl = String.format(GET_SERVERLIST_URL_FORMART, PRODUCT_NAMING, "cluster01");
String response = SimpleHttpTestUtils.doGet(getUrl, params, "UTF-8");
System.err.println(response);
}
@Test
public void deleteClusterWithProductAndCluster() {
HashMap<String, String> params = new HashMap<>();
params.put("product", PRODUCT_NAMING);
params.put("cluster", "cluster01");
String response = SimpleHttpTestUtils.doDelete("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
System.err.println(response);
}
@Test
public void deleteClusterWithProductAndClusterAndIp() {
HashMap<String, String> params = new HashMap<>();
params.put("product", PRODUCT_NAMING);
params.put("cluster", "cluster01");
params.put("ips", "127.0.0.200");
String response = SimpleHttpTestUtils.doDelete("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
System.err.println(response);
}
@Test
public void putClusterWithProductAndCluster() {
String ips = "127.0.0.171";
HashMap<String, String> params = new HashMap<>();
params.put("ips", ips);
params.put("product", PRODUCT_NAMING);
params.put("cluster", "cluster01");
String response = SimpleHttpTestUtils.doPut("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
System.err.println(response);
params.add("ips", ips);
params.add("product", PRODUCT_NAMING);
params.add("cluster", "cluster01");
final ResponseEntity<String> postClusterResponseEntity = restTemplate.exchange(
RequestEntity.post("/nacos/v1/as/nodes").header(HttpHeaders.AUTHORIZATION, HTTP_BASIC_INFO)
.body(params), String.class);
Assert.assertNotNull(postClusterResponseEntity);
Assert.assertEquals(HttpStatus.OK.value(), postClusterResponseEntity.getStatusCodeValue());
TimeUnit.MILLISECONDS.sleep(500L);
final ResponseEntity<String> getClusterResponseEntity = restTemplate.exchange(
RequestEntity.get("/{product}/{cluster}", PRODUCT_NAMING, "cluster01").build(), String.class);
Assert.assertNotNull(getClusterResponseEntity);
Assert.assertEquals(HttpStatus.OK.value(), getClusterResponseEntity.getStatusCodeValue());
final String body = getClusterResponseEntity.getBody();
Assert.assertNotNull(body);
}
@Test
public void deleteClusterWithProductAndCluster() throws InterruptedException {
LinkedMultiValueMap<String, String> params = new LinkedMultiValueMap<>(1);
params.add("ips", "127.0.0.104");
params.add("product", PRODUCT_NAMING);
params.add("cluster", "cluster01");
final ResponseEntity<String> postClusterResponseEntity = restTemplate.exchange(
RequestEntity.post("/nacos/v1/as/nodes").header(HttpHeaders.AUTHORIZATION, HTTP_BASIC_INFO)
.body(params), String.class);
Assert.assertNotNull(postClusterResponseEntity);
Assert.assertEquals(HttpStatus.OK.value(), postClusterResponseEntity.getStatusCodeValue());
TimeUnit.MILLISECONDS.sleep(500L);
final ResponseEntity<String> deleteClusterResponseEntity = restTemplate.exchange(
RequestEntity.delete("/nacos/v1/as/nodes?product={product}&cluster={cluster}&ips={ips}", PRODUCT_NAMING,
"cluster01", "127.0.0.104").header(HttpHeaders.AUTHORIZATION, HTTP_BASIC_INFO).build(),
String.class);
Assert.assertNotNull(deleteClusterResponseEntity);
Assert.assertEquals(HttpStatus.OK.value(), deleteClusterResponseEntity.getStatusCodeValue());
}
}

View File

@ -1,176 +0,0 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.address;
import com.alibaba.nacos.common.utils.IoUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Map;
public class SimpleHttpTestUtils {
private static final String REQUEST_METHOD_DELETE = "DELETE";
private static final String REQUEST_METHOD_PUT = "PUT";
private static final String REQUEST_METHOD_POST = "POST";
private static final String REQUEST_METHOD_GET = "GET";
/**
* 连接超时.
*/
private static final int CONNECT_TIME_OUT = 2000;
/**
* 读取数据超时.
*/
private static final int READ_TIME_OUT = 2000;
/**
* 请求编码.
*/
public static final String REQUEST_ENCODING = "UTF-8";
/**
* 接收编码.
*/
public static final String RESPONSE_ENCODING = "UTF-8";
public static final short OK = 200;
public static final short BAD_REQUEST = 400;
public static final short INTERNAL_SERVER_ERROR = 500;
public static final short PARAM_ERROR_NO_ANALYSESOR = 1000;
/**
* 发送带参数的GET的HTTP请求.
*
* @param reqUrl HTTP请求URL
* @param paramMap 参数映射表
* @return HTTP响应的字符串
*/
public static String doGet(String reqUrl, Map<String, String> paramMap, String recvEncoding) {
return doRequest(reqUrl, paramMap, REQUEST_METHOD_GET, recvEncoding);
}
/**
* 发送带参数的POST的HTTP请求.
*
* @param reqUrl HTTP请求URL
* @param paramMap 参数映射表
* @return HTTP响应的字符串
*/
public static String doPost(String reqUrl, Map<String, String> paramMap, String recvEncoding) {
return doRequest(reqUrl, paramMap, REQUEST_METHOD_POST, recvEncoding);
}
/**
* 发送带参数的 PUT HTTP 请求.
*
* @param reqUrl HTTP请求URL
* @param paramMap 参数映射表
* @return HTTP响应的字符串
*/
public static String doPut(String reqUrl, Map<String, String> paramMap, String recvEncoding) {
return doRequest(reqUrl, paramMap, REQUEST_METHOD_PUT, recvEncoding);
}
/**
* 发送带参数的 DELETE HTTP 请求.
*
* @param reqUrl HTTP请求URL
* @param paramMap 参数映射表
* @return HTTP响应的字符串
*/
public static String doDelete(String reqUrl, Map<String, String> paramMap, String recvEncoding) {
return doRequest(reqUrl, paramMap, REQUEST_METHOD_DELETE, recvEncoding);
}
private static String doRequest(String reqUrl, Map<String, String> paramMap, String reqMethod,
String recvEncoding) {
return doExecute(reqUrl, paramMap, reqMethod, recvEncoding);
}
private static String doExecute(String reqUrl, Map<String, String> paramMap, String reqMethod,
String recvEncoding) {
HttpURLConnection urlCon = null;
String responseContent = null;
try {
StringBuilder params = new StringBuilder();
if (paramMap != null) {
for (Map.Entry<String, String> element : paramMap.entrySet()) {
params.append(element.getKey());
params.append('=');
params.append(URLEncoder.encode(element.getValue(), REQUEST_ENCODING));
params.append('&');
}
if (params.length() > 0) {
params = params.deleteCharAt(params.length() - 1);
}
if (params.length() > 0 && (REQUEST_METHOD_GET.equals(reqMethod) || REQUEST_METHOD_DELETE
.equals(reqMethod))) {
reqUrl = reqUrl + "?" + params.toString();
}
}
URL url = new URL(reqUrl);
urlCon = (HttpURLConnection) url.openConnection();
urlCon.setRequestMethod(reqMethod);
urlCon.setConnectTimeout(CONNECT_TIME_OUT);
urlCon.setReadTimeout(READ_TIME_OUT);
urlCon.setDoOutput(true);
if (REQUEST_METHOD_POST.equals(reqMethod) || REQUEST_METHOD_PUT.equals(reqMethod)) {
byte[] b = params.toString().getBytes();
urlCon.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
urlCon.setRequestProperty("Content-Length", String.valueOf(b.length));
urlCon.getOutputStream().write(b, 0, b.length);
urlCon.getOutputStream().flush();
urlCon.getOutputStream().close();
}
InputStream in = urlCon.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(in, recvEncoding));
String tempLine = rd.readLine();
StringBuffer tempStr = new StringBuffer();
while (tempLine != null) {
tempStr.append(tempLine);
tempLine = rd.readLine();
}
responseContent = tempStr.toString();
rd.close();
in.close();
urlCon.getResponseMessage();
} catch (IOException e) {
e.printStackTrace();
} finally {
IoUtils.closeQuietly(urlCon);
}
return responseContent;
}
}

View File

@ -0,0 +1,110 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.address.component;
import com.alibaba.nacos.address.constant.AddressServerConstants;
import com.alibaba.nacos.naming.core.Instance;
import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
public class AddressServerGeneratorManagerTest {
@Test
public void testGenerateProductName() {
AddressServerGeneratorManager manager = new AddressServerGeneratorManager();
final String blankName = manager.generateProductName("");
Assert.assertEquals(AddressServerConstants.ALIWARE_NACOS_DEFAULT_PRODUCT_NAME, blankName);
final String defaultName = manager.generateProductName(AddressServerConstants.DEFAULT_PRODUCT);
Assert.assertEquals(AddressServerConstants.ALIWARE_NACOS_DEFAULT_PRODUCT_NAME, defaultName);
final String testName = manager.generateProductName("test");
Assert.assertEquals("nacos.as.test", testName);
}
@Test
public void testGenerateInstancesByIps() {
AddressServerGeneratorManager manager = new AddressServerGeneratorManager();
final List<Instance> empty = manager.generateInstancesByIps(null, null, null, null);
Assert.assertNotNull(empty);
Assert.assertTrue(empty.isEmpty());
String[] ipArray = new String[]{"192.168.3.1:8848", "192.168.3.2:8848", "192.168.3.3:8848"};
final List<Instance> instanceList = manager.generateInstancesByIps("DEFAULT_GROUP@@nacos.as.test", "test", "test",
ipArray);
Assert.assertNotNull(instanceList);
Assert.assertFalse(instanceList.isEmpty());
Assert.assertEquals(3, instanceList.size());
final Instance instance1 = instanceList.get(0);
Assert.assertEquals("192.168.3.1", instance1.getIp());
final Instance instance2 = instanceList.get(1);
Assert.assertEquals("192.168.3.2", instance2.getIp());
final Instance instance3 = instanceList.get(2);
Assert.assertEquals("192.168.3.3", instance3.getIp());
}
@Test
public void testGenerateResponseIps() {
final List<Instance> instanceList = new ArrayList<>();
Instance instance1 = new Instance();
instance1.setIp("192.168.3.1");
instance1.setPort(8848);
Instance instance2 = new Instance();
instance2.setIp("192.168.3.2");
instance2.setPort(8848);
Instance instance3 = new Instance();
instance3.setIp("192.168.3.3");
instance3.setPort(8848);
instanceList.add(instance1);
instanceList.add(instance2);
instanceList.add(instance3);
AddressServerGeneratorManager manager = new AddressServerGeneratorManager();
final String ipListStr = manager.generateResponseIps(instanceList);
StringBuilder expectStr = new StringBuilder();
final StringBuilder ret = expectStr
.append("192.168.3.1:8848").append('\n')
.append("192.168.3.2:8848").append('\n')
.append("192.168.3.3:8848").append('\n');
Assert.assertEquals(ret.toString(), ipListStr);
}
@Test
public void testGenerateNacosServiceName() {
AddressServerGeneratorManager manager = new AddressServerGeneratorManager();
final String containDefault = manager.generateNacosServiceName("DEFAULT_GROUP@@test");
Assert.assertEquals("DEFAULT_GROUP@@test", containDefault);
final String product = manager.generateNacosServiceName("product");
Assert.assertEquals("DEFAULT_GROUP@@product", product);
}
}

View File

@ -41,4 +41,23 @@ public class AddressServerManagerTests {
assertEquals("otherServerList", ADDRESS_SERVER_MANAGER.getDefaultClusterNameIfEmpty("otherServerList"));
}
@Test
public void testGetRawClusterName() {
assertEquals("serverList", ADDRESS_SERVER_MANAGER.getRawClusterName("serverList"));
assertEquals(AddressServerConstants.DEFAULT_GET_CLUSTER, ADDRESS_SERVER_MANAGER.getRawClusterName(""));
}
@Test
public void testSplitIps() {
final String[] emptyArr = ADDRESS_SERVER_MANAGER.splitIps("");
assertEquals(0, emptyArr.length);
final String[] one = ADDRESS_SERVER_MANAGER.splitIps("192.168.1.12:8848");
assertEquals(1, one.length);
assertEquals("192.168.1.12:8848", one[0]);
final String[] two = ADDRESS_SERVER_MANAGER.splitIps("192.168.1.12:8848,192.268.3.33:8848");
assertEquals(2, two.length);
assertEquals("192.168.1.12:8848", two[0]);
assertEquals("192.268.3.33:8848", two[1]);
}
}

View File

@ -0,0 +1,163 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.address.controller;
import com.alibaba.nacos.address.component.AddressServerGeneratorManager;
import com.alibaba.nacos.address.component.AddressServerManager;
import com.alibaba.nacos.address.constant.AddressServerConstants;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.naming.core.Service;
import com.alibaba.nacos.naming.core.ServiceManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(MockitoJUnitRunner.class)
public class AddressServerClusterControllerTest {
@Mock
private ServiceManager serviceManager;
private MockMvc mockMvc;
@Before
public void before() {
mockMvc = MockMvcBuilders.standaloneSetup(new AddressServerClusterController(serviceManager, new AddressServerManager(),
new AddressServerGeneratorManager())).build();
}
@Test
public void testPostCluster() throws Exception {
mockMvc.perform(post("/nacos/v1/as/nodes")
.param("product", "default")
.param("cluster", "serverList")
.param("ips", "192.168.3.1,192.168.3.2"))
.andExpect(status().isOk());
}
@Test
public void testPostClusterWithErrorIps() throws Exception {
mockMvc.perform(post("/nacos/v1/as/nodes")
.param("product", "default")
.param("cluster", "serverList")
.param("ips", "192.168.1"))
.andExpect(status().isBadRequest());
}
@Test
public void testPostClusterThrowException() throws Exception {
Mockito.doThrow(new NacosException(500, "create service error")).when(serviceManager)
.createServiceIfAbsent(Mockito.eq(Constants.DEFAULT_NAMESPACE_ID), Mockito.eq(
Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default"),
Mockito.eq(false), Mockito.any());
mockMvc.perform(post("/nacos/v1/as/nodes")
.param("product", "default")
.param("cluster", "serverList")
.param("ips", "192.168.1"))
.andExpect(status().isInternalServerError());
}
@Test
public void testDeleteCluster() throws Exception {
Mockito.when(serviceManager.getService(Mockito.eq(Constants.DEFAULT_NAMESPACE_ID),
Mockito.eq(Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default")))
.thenReturn(new Service(Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default"));
mockMvc.perform(delete("/nacos/v1/as/nodes")
.param("product", "default")
.param("cluster", "serverList")
.param("ips", "192.168.3.1,192.168.3.2")
).andExpect(status().isOk());
}
@Test
public void testDeleteClusterCannotFindService() throws Exception {
mockMvc.perform(delete("/nacos/v1/as/nodes")
.param("product", "default")
.param("cluster", "serverList")
.param("ips", "192.168.3.1,192.168.3.2")
).andExpect(status().isNotFound());
}
@Test
public void testDeleteClusterEmptyIps() throws Exception {
Mockito.when(serviceManager.getService(Mockito.eq(Constants.DEFAULT_NAMESPACE_ID),
Mockito.eq(Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default")))
.thenReturn(new Service(Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default"));
mockMvc.perform(delete("/nacos/v1/as/nodes")
.param("product", "default")
.param("cluster", "serverList")
.param("ips", "")
).andExpect(status().isBadRequest());
}
@Test
public void testDeleteClusterErrorIps() throws Exception {
Mockito.when(serviceManager.getService(Mockito.eq(Constants.DEFAULT_NAMESPACE_ID),
Mockito.eq(Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default")))
.thenReturn(new Service(Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default"));
mockMvc.perform(delete("/nacos/v1/as/nodes")
.param("product", "default")
.param("cluster", "serverList")
.param("ips", "192.168.1")
).andExpect(status().isBadRequest());
}
@Test
public void testDeleteClusterThrowException() throws Exception {
Mockito.when(serviceManager.getService(Mockito.eq(Constants.DEFAULT_NAMESPACE_ID),
Mockito.eq(Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default")))
.thenReturn(new Service(Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default"));
Mockito.doThrow(new NacosException(500, "remove service error"))
.when(serviceManager)
.removeInstance(Mockito.eq(Constants.DEFAULT_NAMESPACE_ID),
Mockito.eq(Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default"),
Mockito.eq(false),
Mockito.any());
mockMvc.perform(delete("/nacos/v1/as/nodes")
.param("product", "default")
.param("cluster", "serverList")
.param("ips", "192.168.3.1,192.168.3.2")
).andExpect(status().isInternalServerError());
}
}

View File

@ -0,0 +1,110 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.address.controller;
import com.alibaba.nacos.address.component.AddressServerGeneratorManager;
import com.alibaba.nacos.address.constant.AddressServerConstants;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.naming.core.Cluster;
import com.alibaba.nacos.naming.core.Instance;
import com.alibaba.nacos.naming.core.Service;
import com.alibaba.nacos.naming.core.ServiceManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(MockitoJUnitRunner.class)
public class ServerListControllerTest {
@Mock
private ServiceManager serviceManager;
private MockMvc mockMvc;
@Before
public void before() {
this.mockMvc = MockMvcBuilders
.standaloneSetup(new ServerListController(serviceManager, new AddressServerGeneratorManager()))
.build();
}
@Test
public void testGetCluster() throws Exception {
final Service service = new Service(
Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default");
Cluster cluster = new Cluster();
cluster.setName("serverList");
cluster.setService(service);
final HashMap<String, Cluster> clusterMap = new HashMap<>(1);
clusterMap.put("serverList", cluster);
service.setClusterMap(clusterMap);
List<Instance> list = new ArrayList<>(2);
list.add(new Instance("192.168.3.1", 8848));
list.add(new Instance("192.168.3.2", 8848));
cluster.updateIps(list, false);
Mockito.when(serviceManager.getService(Mockito.eq(Constants.DEFAULT_NAMESPACE_ID),
Mockito.eq(Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default")))
.thenReturn(service);
mockMvc.perform(get("/nacos/serverList"))
.andExpect(status().isOk());
}
@Test
public void testGetClusterCannotFindService() throws Exception {
mockMvc.perform(get("/default/serverList"))
.andExpect(status().isNotFound());
}
@Test
public void testGetClusterCannotFindCluster() throws Exception {
final Service service = new Service(
Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default");
final HashMap<String, Cluster> clusterMap = new HashMap<>(1);
service.setClusterMap(clusterMap);
Mockito.when(serviceManager.getService(Mockito.eq(Constants.DEFAULT_NAMESPACE_ID),
Mockito.eq(Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default")))
.thenReturn(service);
mockMvc.perform(get("/nacos/serverList"))
.andExpect(status().isNotFound());
}
}

View File

@ -97,10 +97,6 @@
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</dependency>
<dependency>
<groupId>com.google.api.grpc</groupId>
<artifactId>proto-google-common-protos</artifactId>

View File

@ -86,6 +86,10 @@ public class Constants {
public static final String USERNAME = "username";
public static final String TOKEN_REFRESH_WINDOW = "tokenRefreshWindow";
public static final Integer SDK_GRPC_PORT_DEFAULT_OFFSET = 1000;
public static final Integer CLUSTER_GRPC_PORT_DEFAULT_OFFSET = 1001;
/**
* second.
@ -184,7 +188,7 @@ public class Constants {
public static final String NULL_STRING = "null";
public static final String NUMBER_PATTERN = "^\\d+$";
public static final String NUMBER_PATTERN_STRING = "^\\d+$";
public static final String ANY_PATTERN = ".*";
@ -210,6 +214,8 @@ public class Constants {
public static final String CHARSET_KEY = "charset";
public static final String CLUSTER_NAME_PATTERN_STRING = "^[0-9a-zA-Z-]+$";
/**
* The constants in config directory.
*/

View File

@ -65,7 +65,7 @@ public enum ConfigType {
private final String type;
private static final Map<String, ConfigType> LOCAL_MAP = new HashMap<String, ConfigType>();
private static final Map<String, ConfigType> LOCAL_MAP = new HashMap<>();
static {
for (ConfigType configType : values()) {

View File

@ -36,7 +36,7 @@ public interface NacosConfigConverter<T> {
/**
* Convert the Nacos' config of type S to target type T.
*
* @param config the Naocs's config to convert, which must be an instance of S (never {@code null})
* @param config the Nacos's config to convert, which must be an instance of S (never {@code null})
* @return the converted object, which must be an instance of T (potentially {@code null})
*/
T convert(String config);

View File

@ -32,7 +32,7 @@ public class ConfigBatchListenRequest extends AbstractConfigRequest {
*/
private boolean listen = true;
private List<ConfigListenContext> configListenContexts = new ArrayList<ConfigListenContext>();
private List<ConfigListenContext> configListenContexts = new ArrayList<>();
/**
* add listen config.

View File

@ -30,7 +30,7 @@ import java.util.List;
*/
public class ConfigChangeBatchListenResponse extends Response {
List<ConfigContext> changedConfigs = new ArrayList<ConfigContext>();
List<ConfigContext> changedConfigs = new ArrayList<>();
public ConfigChangeBatchListenResponse() {
}

View File

@ -23,7 +23,7 @@ import com.alibaba.nacos.api.remote.response.ResponseCode;
* ConfigPublishResponse.
*
* @author liuzunfei
* @version $Id: ConfigPubishResponse.java, v 0.1 2020年07月16日 4:59 PM liuzunfei Exp $
* @version $Id: ConfigPublishResponse.java, v 0.1 2020年07月16日 4:59 PM liuzunfei Exp $
*/
public class ConfigPublishResponse extends Response {

View File

@ -20,10 +20,10 @@ import com.alibaba.nacos.api.remote.response.Response;
import com.alibaba.nacos.api.remote.response.ResponseCode;
/**
* ConfigPubishResponse.
* ConfigRemoveResponse.
*
* @author liuzunfei
* @version $Id: ConfigPubishResponse.java, v 0.1 2020年07月16日 4:59 PM liuzunfei Exp $
* @version $Id: ConfigRemoveResponse.java, v 0.1 2020年07月16日 4:59 PM liuzunfei Exp $
*/
public class ConfigRemoveResponse extends Response {

View File

@ -33,6 +33,8 @@ public class NacosDeserializationException extends NacosRuntimeException {
private static final String MSG_FOR_SPECIFIED_CLASS = "Nacos deserialize for class [%s] failed. ";
private static final String ERROR_MSG_FOR_SPECIFIED_CLASS = "Nacos deserialize for class [%s] failed, cause error[%s]. ";
private Class<?> targetClass;
public NacosDeserializationException() {
@ -53,12 +55,12 @@ public class NacosDeserializationException extends NacosRuntimeException {
}
public NacosDeserializationException(Class<?> targetClass, Throwable throwable) {
super(DESERIALIZE_ERROR_CODE, String.format(MSG_FOR_SPECIFIED_CLASS, targetClass.getName()), throwable);
super(DESERIALIZE_ERROR_CODE, String.format(ERROR_MSG_FOR_SPECIFIED_CLASS, targetClass.getName(), throwable.getMessage()), throwable);
this.targetClass = targetClass;
}
public NacosDeserializationException(Type targetType, Throwable throwable) {
super(DESERIALIZE_ERROR_CODE, String.format(MSG_FOR_SPECIFIED_CLASS, targetType.toString()), throwable);
super(DESERIALIZE_ERROR_CODE, String.format(ERROR_MSG_FOR_SPECIFIED_CLASS, targetType.toString(), throwable.getMessage()), throwable);
}
public Class<?> getTargetClass() {

View File

@ -613,8 +613,7 @@ private static final long serialVersionUID = 0L;
Metadata, Metadata.Builder, MetadataOrBuilder>
getMetadataFieldBuilder() {
if (metadataBuilder_ == null) {
metadataBuilder_ = new com.google.protobuf.SingleFieldBuilderV3<
Metadata, Metadata.Builder, MetadataOrBuilder>(
metadataBuilder_ = new com.google.protobuf.SingleFieldBuilderV3<>(
getMetadata(),
getParentForChildren(),
isClean());
@ -730,8 +729,7 @@ private static final long serialVersionUID = 0L;
com.google.protobuf.Any, com.google.protobuf.Any.Builder, com.google.protobuf.AnyOrBuilder>
getBodyFieldBuilder() {
if (bodyBuilder_ == null) {
bodyBuilder_ = new com.google.protobuf.SingleFieldBuilderV3<
com.google.protobuf.Any, com.google.protobuf.Any.Builder, com.google.protobuf.AnyOrBuilder>(
bodyBuilder_ = new com.google.protobuf.SingleFieldBuilderV3<>(
getBody(),
getParentForChildren(),
isClean());

View File

@ -96,6 +96,17 @@ public interface NamingService {
*/
void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException;
/**
* batch register instance to service with specified instance properties.
*
* @param serviceName name of service
* @param groupName group of service
* @param instances instances to register
* @throws NacosException nacos exception
* @since 2.1.1
*/
void batchRegisterInstance(String serviceName, String groupName, List<Instance> instances) throws NacosException;
/**
* deregister instance from a service.
*

View File

@ -66,7 +66,7 @@ public class Cluster implements Serializable {
*/
private boolean useIPPort4Check = true;
private Map<String, String> metadata = new HashMap<String, String>();
private Map<String, String> metadata = new HashMap<>();
public Cluster() {

View File

@ -18,7 +18,7 @@ package com.alibaba.nacos.api.naming.pojo;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.naming.PreservedMetadataKeys;
import com.alibaba.nacos.api.utils.StringUtils;
import com.alibaba.nacos.api.naming.utils.NamingUtils;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
@ -26,8 +26,6 @@ import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import static com.alibaba.nacos.api.common.Constants.NUMBER_PATTERN;
/**
* Instance.
*
@ -88,7 +86,7 @@ public class Instance implements Serializable {
/**
* user extended attributes.
*/
private Map<String, String> metadata = new HashMap<String, String>();
private Map<String, String> metadata = new HashMap<>();
public String getInstanceId() {
return this.instanceId;
@ -162,7 +160,7 @@ public class Instance implements Serializable {
*/
public void addMetadata(final String key, final String value) {
if (metadata == null) {
metadata = new HashMap<String, String>(4);
metadata = new HashMap<>(4);
}
metadata.put(key, value);
}
@ -252,7 +250,7 @@ public class Instance implements Serializable {
return defaultValue;
}
final String value = getMetadata().get(key);
if (!StringUtils.isEmpty(value) && value.matches(NUMBER_PATTERN)) {
if (NamingUtils.isNumber(value)) {
return Long.parseLong(value);
}
return defaultValue;

View File

@ -54,7 +54,7 @@ public class Service implements Serializable {
*/
private String groupName;
private Map<String, String> metadata = new HashMap<String, String>();
private Map<String, String> metadata = new HashMap<>();
public Service() {
}

View File

@ -55,7 +55,7 @@ public class ServiceInfo {
private long cacheMillis = 1000L;
private List<Instance> hosts = new ArrayList<Instance>();
private List<Instance> hosts = new ArrayList<>();
private long lastRefTime = 0L;
@ -77,7 +77,7 @@ public class ServiceInfo {
}
/**
* There is only one form of the key:groupName@@name@clusters. This constuctor used by DiskCache.read(String) and
* There is only one form of the key:groupName@@name@clusters. This constructor used by DiskCache.read(String) and
* FailoverReactor.FailoverFileReader,you should know that 'groupName' must not be null,and 'clusters' can be null.
*/
public ServiceInfo(String key) {
@ -96,7 +96,7 @@ public class ServiceInfo {
this.name = keys[serviceNameIndex];
} else {
//defensive programming
throw new IllegalArgumentException("Cann't parse out 'groupName',but it must not be null!");
throw new IllegalArgumentException("Can't parse out 'groupName',but it must not be null!");
}
}
@ -126,7 +126,7 @@ public class ServiceInfo {
}
public List<Instance> getHosts() {
return new ArrayList<Instance>(hosts);
return new ArrayList<>(hosts);
}
public boolean isValid() {
@ -187,7 +187,7 @@ public class ServiceInfo {
return false;
}
List<Instance> validHosts = new ArrayList<Instance>();
List<Instance> validHosts = new ArrayList<>();
for (Instance host : hosts) {
if (!host.isHealthy()) {
continue;

View File

@ -54,7 +54,7 @@ public enum HealthCheckType {
* In JDK 1.6, the map need full class for general. So ignore check style.
*/
@SuppressWarnings("checkstyle:linelength")
private static final Map<String, Class<? extends AbstractHealthChecker>> EXTEND = new ConcurrentHashMap<String, Class<? extends AbstractHealthChecker>>();
private static final Map<String, Class<? extends AbstractHealthChecker>> EXTEND = new ConcurrentHashMap<>();
HealthCheckType(Class<? extends AbstractHealthChecker> healthCheckerClass) {
this.healthCheckerClass = healthCheckerClass;
@ -90,7 +90,7 @@ public enum HealthCheckType {
}
public static List<Class<? extends AbstractHealthChecker>> getLoadedHealthCheckerClasses() {
List<Class<? extends AbstractHealthChecker>> all = new ArrayList<Class<? extends AbstractHealthChecker>>();
List<Class<? extends AbstractHealthChecker>> all = new ArrayList<>();
for (HealthCheckType type : values()) {
all.add(type.healthCheckerClass);
}

View File

@ -76,7 +76,7 @@ public class Http extends AbstractHealthChecker {
if (StringUtils.isBlank(headers)) {
return Collections.emptyMap();
}
final Map<String, String> headerMap = new HashMap<String, String>(16);
final Map<String, String> headerMap = new HashMap<>(16);
for (final String s : headers.split(Constants.NAMING_HTTP_HEADER_SPLITTER)) {
final String[] splits = s.split(":");
if (splits.length != 2) {

View File

@ -26,6 +26,8 @@ public class NamingRemoteConstants {
public static final String REGISTER_INSTANCE = "registerInstance";
public static final String BATCH_REGISTER_INSTANCE = "batchRegisterInstance";
public static final String DE_REGISTER_INSTANCE = "deregisterInstance";
public static final String QUERY_SERVICE = "queryService";

View File

@ -0,0 +1,62 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.naming.remote.request;
import com.alibaba.nacos.api.naming.pojo.Instance;
import java.util.List;
/**
* The client registers multiple service instance request.
*
* @author <a href="mailto:chenhao26@xiaomi.com">chenhao26</a>
*/
public class BatchInstanceRequest extends AbstractNamingRequest {
private String type;
/**
* save all service instance.
*/
private List<Instance> instances;
public BatchInstanceRequest() {
}
public BatchInstanceRequest(String namespace, String serviceName, String groupName, String type,
List<Instance> instances) {
super(namespace, serviceName, groupName);
this.type = type;
this.instances = instances;
}
public void setType(String type) {
this.type = type;
}
public String getType() {
return this.type;
}
public List<Instance> getInstances() {
return instances;
}
public void setInstances(List<Instance> instances) {
this.instances = instances;
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.naming.remote.response;
import com.alibaba.nacos.api.remote.response.Response;
/**
* batch instance response.
*
* @author <a href="mailto:chenhao26@xiaomi.com">chenhao26</a>
*/
public class BatchInstanceResponse extends Response {
private String type;
public BatchInstanceResponse() {
}
public BatchInstanceResponse(String type) {
this.type = type;
}
public void setType(String type) {
this.type = type;
}
}

View File

@ -21,6 +21,14 @@ import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.utils.StringUtils;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import static com.alibaba.nacos.api.common.Constants.CLUSTER_NAME_PATTERN_STRING;
import static com.alibaba.nacos.api.common.Constants.NUMBER_PATTERN_STRING;
/**
* NamingUtils.
*
@ -29,6 +37,10 @@ import com.alibaba.nacos.api.utils.StringUtils;
*/
public class NamingUtils {
private static final Pattern CLUSTER_NAME_PATTERN = Pattern.compile(CLUSTER_NAME_PATTERN_STRING);
private static final Pattern NUMBER_PATTERN = Pattern.compile(NUMBER_PATTERN_STRING);
/**
* Returns a combined string with serviceName and groupName. serviceName can not be nil.
*
@ -129,5 +141,45 @@ public class NamingUtils {
throw new NacosException(NacosException.INVALID_PARAM,
"Instance 'heart beat interval' must less than 'heart beat timeout' and 'ip delete timeout'.");
}
if (!StringUtils.isEmpty(instance.getClusterName()) && !CLUSTER_NAME_PATTERN.matcher(instance.getClusterName()).matches()) {
throw new NacosException(NacosException.INVALID_PARAM,
String.format("Instance 'clusterName' should be characters with only 0-9a-zA-Z-. (current: %s)",
instance.getClusterName()));
}
}
/**
* check batch register is Ephemeral.
* @param instance instance
* @throws NacosException NacosException
*/
public static void checkInstanceIsEphemeral(Instance instance) throws NacosException {
if (!instance.isEphemeral()) {
throw new NacosException(NacosException.INVALID_PARAM,
String.format("Batch registration does not allow persistent instance registration , Instance%s", instance));
}
}
/**
* Batch verify the validity of instances.
* @param instances List of instances to be registered
* @throws NacosException Nacos
*/
public static void batchCheckInstanceIsLegal(List<Instance> instances) throws NacosException {
Set<Instance> newInstanceSet = new HashSet<>(instances);
for (Instance instance : newInstanceSet) {
checkInstanceIsEphemeral(instance);
checkInstanceIsLegal(instance);
}
}
/**
* Check string is a number or not.
*
* @param str a string of digits
* @return if it is a string of digits, return true
*/
public static boolean isNumber(String str) {
return !StringUtils.isEmpty(str) && NUMBER_PATTERN.matcher(str).matches();
}
}

View File

@ -17,7 +17,6 @@
package com.alibaba.nacos.api.remote;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
/**
* rpc scheduler executor .
@ -34,12 +33,7 @@ public class RpcScheduledExecutor extends ScheduledThreadPoolExecutor {
"com.alibaba.nacos.remote.ServerCommonScheduler");
public RpcScheduledExecutor(int corePoolSize, final String threadName) {
super(corePoolSize, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, threadName);
}
});
super(corePoolSize, r -> new Thread(r, threadName));
}
}

View File

@ -35,7 +35,7 @@ public class ConnectionSetupRequest extends InternalRequest {
private String tenant;
private Map<String, String> labels = new HashMap<String, String>();
private Map<String, String> labels = new HashMap<>();
public ConnectionSetupRequest() {
}

View File

@ -33,7 +33,7 @@ public class RequestMeta {
private String clientVersion = "";
private Map<String, String> labels = new HashMap<String, String>();
private Map<String, String> labels = new HashMap<>();
/**
* Getter method for property <tt>clientVersion</tt>.

View File

@ -16,6 +16,9 @@
package com.alibaba.nacos.api.remote.response;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.runtime.NacosRuntimeException;
/**
* UnKnowResponse.
*
@ -37,4 +40,24 @@ public class ErrorResponse extends Response {
return response;
}
/**
* build an error response.
*
* @param exception exception
* @return response
*/
public static Response build(Throwable exception) {
int errorCode;
if (exception instanceof NacosException) {
errorCode = ((NacosException) exception).getErrCode();
} else if (exception instanceof NacosRuntimeException) {
errorCode = ((NacosRuntimeException) exception).getErrCode();
} else {
errorCode = ResponseCode.FAIL.getCode();
}
ErrorResponse response = new ErrorResponse();
response.setErrorInfo(errorCode, exception.getMessage());
return response;
}
}

View File

@ -29,7 +29,7 @@ public class ServerLoaderInfoResponse extends Response {
String address;
Map<String, String> loaderMetrics = new HashMap<String, String>();
Map<String, String> loaderMetrics = new HashMap<>();
public String getMetricsValue(String key) {
return loaderMetrics.get(key);

View File

@ -41,7 +41,7 @@ service Request {
}
service BiRequestStream {
// Sends a commonRequest
// Sends a biStreamRequest
rpc requestBiStream (stream Payload) returns (stream Payload) {
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright 1999-2020 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.naming.pojo;
import junit.framework.TestCase;
import org.junit.Test;
public class InstanceTest extends TestCase {
@Test
public void testCheckClusterNameFormat() {
Instance instance = new Instance();
instance.setClusterName("demo");
assertEquals("demo", instance.getClusterName());
}
}

View File

@ -16,10 +16,20 @@
package com.alibaba.nacos.api.naming.utils;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.PreservedMetadataKeys;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.utils.StringUtils;
import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class NamingUtilsTest {
@ -34,4 +44,126 @@ public class NamingUtilsTest {
String groupNameAndServiceName = NamingUtils.getGroupedNameOptional("serviceA", "groupA");
assertEquals("groupA@@serviceA", groupNameAndServiceName);
}
@Test
public void testCheckInstanceIsLegal() throws NacosException {
// check invalid clusterName
Instance instance = new Instance();
instance.setClusterName("cluster1,cluster2");
try {
NamingUtils.checkInstanceIsLegal(instance);
assertTrue(false);
} catch (Exception e) {
assertTrue(NacosException.class.equals(e.getClass()));
assertEquals(
"Instance 'clusterName' should be characters with only 0-9a-zA-Z-. (current: cluster1,cluster2)",
e.getMessage());
}
// valid clusterName
instance.setClusterName("cluster1");
NamingUtils.checkInstanceIsLegal(instance);
assertTrue(true);
// check heartBeatTimeout, heartBeatInterval, ipDeleteTimeout
Map<String, String> meta = new HashMap<>();
meta.put(PreservedMetadataKeys.HEART_BEAT_TIMEOUT, "1");
meta.put(PreservedMetadataKeys.HEART_BEAT_INTERVAL, "2");
meta.put(PreservedMetadataKeys.IP_DELETE_TIMEOUT, "1");
instance.setMetadata(meta);
try {
NamingUtils.checkInstanceIsLegal(instance);
assertTrue(false);
} catch (Exception e) {
assertTrue(NacosException.class.equals(e.getClass()));
assertEquals(
"Instance 'heart beat interval' must less than 'heart beat timeout' and 'ip delete timeout'.",
e.getMessage());
}
meta.put(PreservedMetadataKeys.HEART_BEAT_TIMEOUT, "3");
meta.put(PreservedMetadataKeys.HEART_BEAT_INTERVAL, "2");
meta.put(PreservedMetadataKeys.IP_DELETE_TIMEOUT, "3");
NamingUtils.checkInstanceIsLegal(instance);
assertTrue(true);
}
@Test
public void testBatchCheckInstanceIsLegal() throws NacosException {
// check invalid clusterName
Instance instance = new Instance();
instance.setClusterName("cluster1,cluster2");
List<Instance> instanceList = new ArrayList<>();
instanceList.add(instance);
try {
NamingUtils.batchCheckInstanceIsLegal(instanceList);
assertTrue(false);
} catch (Exception e) {
assertTrue(NacosException.class.equals(e.getClass()));
assertEquals(
"Instance 'clusterName' should be characters with only 0-9a-zA-Z-. (current: cluster1,cluster2)",
e.getMessage());
}
instanceList.remove(instance);
// TODO valid clusterName
instance.setClusterName("cluster1");
instanceList.add(instance);
NamingUtils.batchCheckInstanceIsLegal(instanceList);
assertTrue(true);
instanceList.remove(instance);
// check heartBeatTimeout, heartBeatInterval, ipDeleteTimeout
Map<String, String> meta = new HashMap<>();
meta.put(PreservedMetadataKeys.HEART_BEAT_TIMEOUT, "1");
meta.put(PreservedMetadataKeys.HEART_BEAT_INTERVAL, "2");
meta.put(PreservedMetadataKeys.IP_DELETE_TIMEOUT, "1");
instance.setMetadata(meta);
instanceList.add(instance);
try {
NamingUtils.batchCheckInstanceIsLegal(instanceList);
assertTrue(false);
} catch (Exception e) {
assertTrue(NacosException.class.equals(e.getClass()));
assertEquals(
"Instance 'heart beat interval' must less than 'heart beat timeout' and 'ip delete timeout'.",
e.getMessage());
}
instanceList.remove(instance);
meta.put(PreservedMetadataKeys.HEART_BEAT_TIMEOUT, "3");
meta.put(PreservedMetadataKeys.HEART_BEAT_INTERVAL, "2");
meta.put(PreservedMetadataKeys.IP_DELETE_TIMEOUT, "3");
instance.setMetadata(meta);
instanceList.add(instance);
NamingUtils.batchCheckInstanceIsLegal(instanceList);
assertTrue(true);
}
@Test
public void testCheckInstanceIsEphemeral() throws NacosException {
Instance instance = new Instance();
instance.setIp("127.0.0.1");
instance.setPort(9089);
instance.setEphemeral(true);
NamingUtils.checkInstanceIsEphemeral(instance);
try {
instance = new Instance();
instance.setIp("127.0.0.1");
instance.setPort(9089);
instance.setEphemeral(false);
NamingUtils.checkInstanceIsEphemeral(instance);
} catch (NacosException e) {
Assert.assertEquals(e.getErrCode(), NacosException.INVALID_PARAM);
}
}
@Test
public void testIsNumber() {
String str1 = "abc";
assertTrue(!NamingUtils.isNumber(str1));
String str2 = "123456";
assertTrue(NamingUtils.isNumber(str2));
}
}

View File

@ -0,0 +1,72 @@
/*
* Copyright 1999-2020 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.remote.response;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.runtime.NacosRuntimeException;
import org.junit.Assert;
import org.junit.Test;
public class ErrorResponseTest {
@Test
public void testBuildWithErrorCode() {
int errorCode = 500;
String msg = "err msg";
Response response = ErrorResponse.build(errorCode, msg);
Assert.assertEquals(errorCode, response.getErrorCode());
Assert.assertEquals(msg, response.getMessage());
}
@Test
public void testBuildWithThrowable() {
String errMsg = "exception msg";
RuntimeException runtimeException = new RuntimeException(errMsg);
Response response = ErrorResponse.build(runtimeException);
Assert.assertEquals(ResponseCode.FAIL.getCode(), response.getErrorCode());
Assert.assertEquals(errMsg, response.getMessage());
}
@Test
public void testBuildWithNacosException() {
int errCode = 500;
String errMsg = "nacos exception msg";
NacosException nacosException = new NacosException(errCode, errMsg);
Response response = ErrorResponse.build(nacosException);
Assert.assertEquals(errCode, response.getErrorCode());
Assert.assertEquals(errMsg, response.getMessage());
}
@Test
public void testBuildWithNacosRuntimeException() {
int errCode = 500;
String errMsg = "nacos runtime exception msg";
NacosRuntimeException nacosRuntimeException = new NacosRuntimeException(errCode, errMsg);
Response response = ErrorResponse.build(nacosRuntimeException);
Assert.assertEquals(errCode, response.getErrorCode());
Assert.assertEquals("errCode: " + errCode + ", errMsg: " + errMsg + " ", response.getMessage());
}
}

View File

@ -87,11 +87,9 @@ public class AuthConfigs extends Subscriber<ServerConfigChangeEvent> {
for (String each : properties.stringPropertyNames()) {
int typeIndex = each.indexOf('.');
String type = each.substring(0, typeIndex);
if (!newProperties.containsKey(type)) {
newProperties.put(type, new Properties());
}
String subKey = each.substring(typeIndex + 1);
newProperties.get(type).setProperty(subKey, properties.getProperty(each));
newProperties.computeIfAbsent(type, key -> new Properties())
.setProperty(subKey, properties.getProperty(each));
}
authPluginProperties = newProperties;
} catch (Exception e) {

View File

@ -113,11 +113,6 @@
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
</dependency>
<dependency>
<groupId>net.jcip</groupId>
<artifactId>jcip-annotations</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>

View File

@ -67,8 +67,8 @@ public class HttpLoginProcessor implements LoginProcessor {
url = server + contextPath + LOGIN_URL;
}
Map<String, String> params = new HashMap<String, String>(2);
Map<String, String> bodyMap = new HashMap<String, String>(2);
Map<String, String> params = new HashMap<>(2);
Map<String, String> bodyMap = new HashMap<>(2);
params.put(PropertyKeyConst.USERNAME, properties.getProperty(PropertyKeyConst.USERNAME, StringUtils.EMPTY));
bodyMap.put(PropertyKeyConst.PASSWORD, properties.getProperty(PropertyKeyConst.PASSWORD, StringUtils.EMPTY));
try {
@ -91,7 +91,7 @@ public class HttpLoginProcessor implements LoginProcessor {
}
return loginIdentityContext;
} catch (Exception e) {
SECURITY_LOGGER.error("[ NacosClientAuthServiceImpl] login http request failed"
SECURITY_LOGGER.error("[NacosClientAuthServiceImpl] login http request failed"
+ " url: {}, params: {}, bodyMap: {}, errorMsg: {}", url, params, bodyMap, e.getMessage());
return null;
}

View File

@ -31,7 +31,7 @@ public final class CredentialService implements SpasCredentialLoader {
private static final Logger LOGGER = LogUtils.logger(CredentialService.class);
private static final ConcurrentHashMap<String, CredentialService> INSTANCES = new ConcurrentHashMap<String, CredentialService>();
private static final ConcurrentHashMap<String, CredentialService> INSTANCES = new ConcurrentHashMap<>();
private final String appName;

View File

@ -70,9 +70,7 @@ public class ConfigResourceInjector extends AbstractResourceInjector {
}
Map<String, String> signHeaders = SpasAdapter
.getSignHeaders(getResource(resource.getNamespace(), resource.getGroup()), secretKey);
if (signHeaders != null && !signHeaders.isEmpty()) {
result.setParameters(signHeaders);
}
result.setParameters(signHeaders);
}
private StsCredential getStsCredential() {

View File

@ -45,7 +45,7 @@ public class SpasAdapter {
private static final String SHA_ENCRYPT = "HmacSHA1";
public static Map<String, String> getSignHeaders(String resource, String secretKey) {
Map<String, String> header = new HashMap<String, String>(2);
Map<String, String> header = new HashMap<>(2);
String timeStamp = String.valueOf(System.currentTimeMillis());
header.put(TIMESTAMP_HEADER, timeStamp);
if (secretKey != null) {

View File

@ -97,9 +97,21 @@ public class NacosConfigService implements ConfigService {
@Override
public String getConfigAndSignListener(String dataId, String group, long timeoutMs, Listener listener)
throws NacosException {
String content = getConfig(dataId, group, timeoutMs);
worker.addTenantListenersWithContent(dataId, group, content, Arrays.asList(listener));
return content;
group = StringUtils.isBlank(group) ? Constants.DEFAULT_GROUP : group.trim();
ConfigResponse configResponse = worker.getAgent()
.queryConfig(dataId, group, worker.getAgent().getTenant(), timeoutMs, false);
String content = configResponse.getContent();
String encryptedDataKey = configResponse.getEncryptedDataKey();
worker.addTenantListenersWithContent(dataId, group, content, encryptedDataKey, Arrays.asList(listener));
// get a decryptContent, fix https://github.com/alibaba/nacos/issues/7039
ConfigResponse cr = new ConfigResponse();
cr.setDataId(dataId);
cr.setGroup(group);
cr.setContent(content);
cr.setEncryptedDataKey(encryptedDataKey);
configFilterChainManager.doFilter(null, cr);
return cr.getContent();
}
@Override
@ -148,7 +160,11 @@ public class NacosConfigService implements ConfigService {
cr.setTenant(tenant);
cr.setGroup(group);
// use local config first
// We first try to use local failover content if exists.
// A config content for failover is not created by client program automatically,
// but is maintained by user.
// This is designed for certain scenario like client emergency reboot,
// changing config needed in the same time, while nacos server is down.
String content = LocalConfigInfoProcessor.getFailover(worker.getAgentName(), dataId, group, tenant);
if (content != null) {
LOGGER.warn("[{}] [get-config] get failover ok, dataId={}, group={}, tenant={}, config={}",
@ -177,13 +193,15 @@ public class NacosConfigService implements ConfigService {
LOGGER.warn("[{}] [get-config] get from server error, dataId={}, group={}, tenant={}, msg={}",
worker.getAgentName(), dataId, group, tenant, ioe.toString());
}
LOGGER.warn("[{}] [get-config] get snapshot ok, dataId={}, group={}, tenant={}, config={}",
worker.getAgentName(), dataId, group, tenant, ContentUtils.truncateContent(content));
content = LocalConfigInfoProcessor.getSnapshot(worker.getAgentName(), dataId, group, tenant);
if (content != null) {
LOGGER.warn("[{}] [get-config] get snapshot ok, dataId={}, group={}, tenant={}, config={}",
worker.getAgentName(), dataId, group, tenant, ContentUtils.truncateContent(content));
}
cr.setContent(content);
String encryptedDataKey = LocalEncryptedDataKeyProcessor
.getEncryptDataKeyFailover(agent.getName(), dataId, group, tenant);
.getEncryptDataKeySnapshot(agent.getName(), dataId, group, tenant);
cr.setEncryptedDataKey(encryptedDataKey);
configFilterChainManager.doFilter(null, cr);
content = cr.getContent();

View File

@ -28,7 +28,7 @@ import java.util.Map;
*/
public class ConfigContext implements IConfigContext {
private final Map<String, Object> param = new HashMap<String, Object>();
private final Map<String, Object> param = new HashMap<>();
@Override
public Object getParameter(String key) {

View File

@ -36,7 +36,7 @@ import static com.alibaba.nacos.client.config.common.ConfigConstants.TYPE;
*/
public class ConfigRequest implements IConfigRequest {
private final Map<String, Object> param = new HashMap<String, Object>();
private final Map<String, Object> param = new HashMap<>();
private final IConfigContext configContext = new ConfigContext();

View File

@ -36,7 +36,7 @@ import static com.alibaba.nacos.client.config.common.ConfigConstants.TENANT;
*/
public class ConfigResponse implements IConfigResponse {
private final Map<String, Object> param = new HashMap<String, Object>();
private final Map<String, Object> param = new HashMap<>();
private final IConfigContext configContext = new ConfigContext();

View File

@ -21,6 +21,7 @@ import com.alibaba.nacos.client.monitor.MetricsMonitor;
import com.alibaba.nacos.common.http.HttpRestResult;
import io.prometheus.client.Histogram;
import java.util.Date;
import java.util.Map;
/**
@ -52,12 +53,14 @@ public class MetricsHttpAgent implements HttpAgent {
@Override
public HttpRestResult<String> httpGet(String path, Map<String, String> headers, Map<String, String> paramValues,
String encode, long readTimeoutMs) throws Exception {
Histogram.Timer timer = MetricsMonitor.getConfigRequestMonitor(GET, path, DEFAULT_CODE);
Date start = new Date();
Histogram.Child histogram = MetricsMonitor.getConfigRequestMonitor(GET, path, DEFAULT_CODE);
HttpRestResult<String> result;
try {
result = httpAgent.httpGet(path, headers, paramValues, encode, readTimeoutMs);
histogram = MetricsMonitor.getConfigRequestMonitor(GET, path, String.valueOf(result.getCode()));
} finally {
timer.observeDuration();
histogram.observe(System.currentTimeMillis() - start.getTime());
}
return result;
@ -66,12 +69,14 @@ public class MetricsHttpAgent implements HttpAgent {
@Override
public HttpRestResult<String> httpPost(String path, Map<String, String> headers, Map<String, String> paramValues,
String encode, long readTimeoutMs) throws Exception {
Histogram.Timer timer = MetricsMonitor.getConfigRequestMonitor(POST, path, DEFAULT_CODE);
Date start = new Date();
Histogram.Child histogram = MetricsMonitor.getConfigRequestMonitor(GET, path, DEFAULT_CODE);
HttpRestResult<String> result;
try {
result = httpAgent.httpPost(path, headers, paramValues, encode, readTimeoutMs);
histogram = MetricsMonitor.getConfigRequestMonitor(GET, path, String.valueOf(result.getCode()));
} finally {
timer.observeDuration();
histogram.observe(System.currentTimeMillis() - start.getTime());
}
return result;
@ -80,12 +85,14 @@ public class MetricsHttpAgent implements HttpAgent {
@Override
public HttpRestResult<String> httpDelete(String path, Map<String, String> headers, Map<String, String> paramValues,
String encode, long readTimeoutMs) throws Exception {
Histogram.Timer timer = MetricsMonitor.getConfigRequestMonitor(DELETE, path, DEFAULT_CODE);
Date start = new Date();
Histogram.Child histogram = MetricsMonitor.getConfigRequestMonitor(GET, path, DEFAULT_CODE);
HttpRestResult<String> result;
try {
result = httpAgent.httpDelete(path, headers, paramValues, encode, readTimeoutMs);
histogram = MetricsMonitor.getConfigRequestMonitor(GET, path, String.valueOf(result.getCode()));
} finally {
timer.observeDuration();
histogram.observe(System.currentTimeMillis() - start.getTime());
}
return result;

View File

@ -225,7 +225,8 @@ public class ServerHttpAgent implements HttpAgent {
private boolean isFail(HttpRestResult<String> result) {
return result.getCode() == HttpURLConnection.HTTP_INTERNAL_ERROR
|| result.getCode() == HttpURLConnection.HTTP_BAD_GATEWAY
|| result.getCode() == HttpURLConnection.HTTP_UNAVAILABLE;
|| result.getCode() == HttpURLConnection.HTTP_UNAVAILABLE
|| result.getCode() == HttpURLConnection.HTTP_NOT_FOUND;
}
public static String getAppname() {

View File

@ -42,7 +42,7 @@ public abstract class AbstractConfigChangeParser implements ConfigChangeParser {
}
protected Map<String, ConfigChangeItem> filterChangeData(Map oldMap, Map newMap) {
Map<String, ConfigChangeItem> result = new HashMap<String, ConfigChangeItem>(16);
Map<String, ConfigChangeItem> result = new HashMap<>(16);
for (Map.Entry<String, Object> e : (Iterable<Map.Entry<String, Object>>) oldMap.entrySet()) {
ConfigChangeItem cci;
if (newMap.containsKey(e.getKey())) {

View File

@ -18,6 +18,7 @@ package com.alibaba.nacos.client.config.impl;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.config.ConfigChangeEvent;
import com.alibaba.nacos.api.config.ConfigChangeItem;
import com.alibaba.nacos.api.config.listener.AbstractSharedListener;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
@ -134,7 +135,7 @@ public class CacheData {
public void setContent(String content) {
this.content = content;
this.md5 = getMd5String(this.content);
this.md5 = getMd5String();
}
/**
@ -168,13 +169,23 @@ public class CacheData {
*
* @param listener listener
*/
public void addListener(Listener listener) {
public void addListener(Listener listener) throws NacosException {
if (null == listener) {
throw new IllegalArgumentException("listener is null");
}
ManagerListenerWrap wrap =
(listener instanceof AbstractConfigChangeListener) ? new ManagerListenerWrap(listener, md5, content)
: new ManagerListenerWrap(listener, md5);
ManagerListenerWrap wrap;
if (listener instanceof AbstractConfigChangeListener) {
ConfigResponse cr = new ConfigResponse();
cr.setDataId(dataId);
cr.setGroup(group);
cr.setContent(content);
cr.setEncryptedDataKey(encryptedDataKey);
configFilterChainManager.doFilter(null, cr);
String contentTmp = cr.getContent();
wrap = new ManagerListenerWrap(listener, md5, contentTmp);
} else {
wrap = new ManagerListenerWrap(listener, md5);
}
if (listeners.addIfAbsent(wrap)) {
LOGGER.info("[{}] [add-listener] ok, tenant={}, dataId={}, group={}, cnt={}", name, tenant, dataId, group,
@ -202,7 +213,7 @@ public class CacheData {
* Returns the iterator on the listener list, read-only. It is guaranteed not to return NULL.
*/
public List<Listener> getListeners() {
List<Listener> result = new ArrayList<Listener>();
List<Listener> result = new ArrayList<>();
for (ManagerListenerWrap wrap : listeners) {
result.add(wrap.listener);
}
@ -317,11 +328,11 @@ public class CacheData {
listener.receiveConfigInfo(contentTmp);
// compare lastContent and content
if (listener instanceof AbstractConfigChangeListener) {
Map data = ConfigChangeHandler.getInstance()
.parseChangeData(listenerWrap.lastContent, content, type);
Map<String, ConfigChangeItem> data = ConfigChangeHandler.getInstance()
.parseChangeData(listenerWrap.lastContent, contentTmp, type);
ConfigChangeEvent event = new ConfigChangeEvent(data);
((AbstractConfigChangeListener) listener).receiveConfigChange(event);
listenerWrap.lastContent = content;
listenerWrap.lastContent = contentTmp;
}
listenerWrap.lastCallMd5 = md5;
@ -331,8 +342,8 @@ public class CacheData {
LOGGER.error("[{}] [notify-error] dataId={}, group={}, md5={}, listener={} errCode={} errMsg={}", name,
dataId, group, md5, listener, ex.getErrCode(), ex.getErrMsg());
} catch (Throwable t) {
LOGGER.error("[{}] [notify-error] dataId={}, group={}, md5={}, listener={} tx={}", name, dataId, group,
md5, listener, t.getCause());
LOGGER.error("[{}] [notify-error] dataId={}, group={}, md5={}, listener={}", name, dataId, group, md5,
listener, t);
} finally {
listenerWrap.inNotifying = false;
Thread.currentThread().setContextClassLoader(myClassLoader);
@ -367,8 +378,8 @@ public class CacheData {
name, (finishNotify - startNotify), dataId, group, md5, listener);
}
public static String getMd5String(String config) {
return (null == config) ? Constants.NULL : MD5Utils.md5Hex(config, Constants.ENCODE);
public String getMd5String() {
return (null == content) ? Constants.NULL : MD5Utils.md5Hex(content, Constants.ENCODE);
}
private String loadCacheContentFromDiskLocal(String name, String dataId, String group, String tenant) {
@ -392,21 +403,7 @@ public class CacheData {
}
public CacheData(ConfigFilterChainManager configFilterChainManager, String name, String dataId, String group) {
if (null == dataId || null == group) {
throw new IllegalArgumentException("dataId=" + dataId + ", group=" + group);
}
this.name = name;
this.configFilterChainManager = configFilterChainManager;
this.dataId = dataId;
this.group = group;
this.tenant = TenantUtil.getUserTenantForAcm();
listeners = new CopyOnWriteArrayList<>();
this.isInitializing = true;
if (initSnapshot) {
this.content = loadCacheContentFromDiskLocal(name, dataId, group, tenant);
this.md5 = getMd5String(content);
}
this.encryptedDataKey = loadEncryptedDataKeyFromDiskLocal(name, dataId, group, tenant);
this(configFilterChainManager, name, dataId, group, TenantUtil.getUserTenantForAcm());
}
public CacheData(ConfigFilterChainManager configFilterChainManager, String name, String dataId, String group,
@ -414,16 +411,17 @@ public class CacheData {
if (null == dataId || null == group) {
throw new IllegalArgumentException("dataId=" + dataId + ", group=" + group);
}
this.name = name;
this.configFilterChainManager = configFilterChainManager;
this.name = name;
this.dataId = dataId;
this.group = group;
this.tenant = tenant;
listeners = new CopyOnWriteArrayList<>();
this.listeners = new CopyOnWriteArrayList<>();
this.isInitializing = true;
if (initSnapshot) {
this.content = loadCacheContentFromDiskLocal(name, dataId, group, tenant);
this.md5 = getMd5String(content);
this.encryptedDataKey = loadEncryptedDataKeyFromDiskLocal(name, dataId, group, tenant);
this.md5 = getMd5String();
}
}
@ -453,8 +451,11 @@ public class CacheData {
final Listener listener;
String lastCallMd5 = CacheData.getMd5String(null);
String lastCallMd5 = Constants.NULL;
/**
* here is a decryptContent.
*/
String lastContent = null;
ManagerListenerWrap(Listener listener) {

View File

@ -138,7 +138,7 @@ public class ClientWorker implements Closeable {
* @param group group of data
* @param listeners listeners
*/
public void addListeners(String dataId, String group, List<? extends Listener> listeners) {
public void addListeners(String dataId, String group, List<? extends Listener> listeners) throws NacosException {
group = blank2defaultGroup(group);
CacheData cache = addCacheDataIfAbsent(dataId, group);
synchronized (cache) {
@ -178,18 +178,20 @@ public class ClientWorker implements Closeable {
/**
* Add listeners for tenant with content.
*
* @param dataId dataId of data
* @param group group of data
* @param content content
* @param listeners listeners
* @param dataId dataId of data
* @param group group of data
* @param content content
* @param encryptedDataKey encryptedDataKey
* @param listeners listeners
* @throws NacosException nacos exception
*/
public void addTenantListenersWithContent(String dataId, String group, String content,
public void addTenantListenersWithContent(String dataId, String group, String content, String encryptedDataKey,
List<? extends Listener> listeners) throws NacosException {
group = blank2defaultGroup(group);
String tenant = agent.getTenant();
CacheData cache = addCacheDataIfAbsent(dataId, group, tenant);
synchronized (cache) {
cache.setEncryptedDataKey(encryptedDataKey);
cache.setContent(content);
for (Listener listener : listeners) {
cache.addListener(listener);
@ -362,6 +364,7 @@ public class ClientWorker implements Closeable {
// fix issue # 1317
if (enableRemoteSyncConfig) {
ConfigResponse response = getServerConfig(dataId, group, tenant, 3000L, false);
cache.setEncryptedDataKey(response.getEncryptedDataKey());
cache.setContent(response.getContent());
}
}
@ -432,8 +435,8 @@ public class ClientWorker implements Closeable {
try {
ConfigResponse response = getServerConfig(cacheData.dataId, cacheData.group, cacheData.tenant, 3000L,
notify);
cacheData.setContent(response.getContent());
cacheData.setEncryptedDataKey(response.getEncryptedDataKey());
cacheData.setContent(response.getContent());
if (null != response.getConfigType()) {
cacheData.setType(response.getConfigType());
}
@ -521,7 +524,7 @@ public class ClientWorker implements Closeable {
public class ConfigRpcTransportClient extends ConfigTransportClient {
private final BlockingQueue<Object> listenExecutebell = new ArrayBlockingQueue<Object>(1);
private final BlockingQueue<Object> listenExecutebell = new ArrayBlockingQueue<>(1);
private Object bellItem = new Object();
@ -575,12 +578,12 @@ public class ClientWorker implements Closeable {
private Map<String, String> getLabels() {
Map<String, String> labels = new HashMap<String, String>(2, 1);
Map<String, String> labels = new HashMap<>(2, 1);
labels.put(RemoteConstants.LABEL_SOURCE, RemoteConstants.LABEL_SOURCE_SDK);
labels.put(RemoteConstants.LABEL_MODULE, RemoteConstants.LABEL_MODULE_CONFIG);
labels.put(Constants.APPNAME, AppNameUtils.getAppName());
labels.put(Constants.VIPSERVER_TAG, EnvUtil.getSelfVipserverTag());
labels.put(Constants.AMORY_TAG, EnvUtil.getSelfAmorayTag());
labels.put(Constants.AMORY_TAG, EnvUtil.getSelfAmoryTag());
labels.put(Constants.LOCATION_TAG, EnvUtil.getSelfLocationTag());
return labels;
@ -665,7 +668,7 @@ public class ClientWorker implements Closeable {
@Override
public List<String> getServerList() {
return ConfigRpcTransportClient.super.serverListManager.serverUrls;
return ConfigRpcTransportClient.super.serverListManager.getServerUrls();
}
});
@ -714,8 +717,8 @@ public class ClientWorker implements Closeable {
@Override
public void executeConfigListen() {
Map<String, List<CacheData>> listenCachesMap = new HashMap<String, List<CacheData>>(16);
Map<String, List<CacheData>> removeListenCachesMap = new HashMap<String, List<CacheData>>(16);
Map<String, List<CacheData>> listenCachesMap = new HashMap<>(16);
Map<String, List<CacheData>> removeListenCachesMap = new HashMap<>(16);
long now = System.currentTimeMillis();
boolean needAllSync = now - lastAllSyncTime >= ALL_SYNC_INTERNAL;
for (CacheData cache : cacheMap.get().values()) {
@ -778,7 +781,7 @@ public class ClientWorker implements Closeable {
rpcClient, configChangeListenRequest);
if (configChangeBatchListenResponse != null && configChangeBatchListenResponse.isSuccess()) {
Set<String> changeKeys = new HashSet<String>();
Set<String> changeKeys = new HashSet<>();
//handle changed keys,notify listener
if (!CollectionUtils.isEmpty(configChangeBatchListenResponse.getChangedConfigs())) {
hasChangedKeys = true;
@ -1072,4 +1075,9 @@ public class ClientWorker implements Closeable {
public String getAgentName() {
return this.agent.getName();
}
public ConfigTransportClient getAgent() {
return this.agent;
}
}

View File

@ -16,6 +16,7 @@
package com.alibaba.nacos.client.config.impl;
import com.alibaba.nacos.api.config.ConfigChangeItem;
import com.alibaba.nacos.api.config.listener.ConfigChangeParser;
import com.alibaba.nacos.common.spi.NacosServiceLoader;
@ -40,7 +41,7 @@ public class ConfigChangeHandler {
}
private ConfigChangeHandler() {
this.parserList = new LinkedList<ConfigChangeParser>();
this.parserList = new LinkedList<>();
Collection<ConfigChangeParser> loader = NacosServiceLoader.load(ConfigChangeParser.class);
Iterator<ConfigChangeParser> itr = loader.iterator();
@ -65,7 +66,7 @@ public class ConfigChangeHandler {
* @return change data map
* @throws IOException io exception
*/
public Map parseChangeData(String oldContent, String newContent, String type) throws IOException {
public Map<String, ConfigChangeItem> parseChangeData(String oldContent, String newContent, String type) throws IOException {
for (ConfigChangeParser changeParser : this.parserList) {
if (changeParser.isResponsibleFor(type)) {
return changeParser.doParse(oldContent, newContent, type);

View File

@ -104,7 +104,7 @@ public abstract class ConfigTransportClient {
* @return headers.
*/
protected Map<String, String> getCommonHeader() {
Map<String, String> headers = new HashMap<String, String>(16);
Map<String, String> headers = new HashMap<>(16);
String ts = String.valueOf(System.currentTimeMillis());
String token = MD5Utils.md5Hex(ts + ParamUtil.getAppKey(), Constants.ENCODE);

View File

@ -196,7 +196,7 @@ public class ServerListManager implements Closeable {
StringTokenizer serverAddrsTokens = new StringTokenizer(this.serverAddrsStr, ",;");
while (serverAddrsTokens.hasMoreTokens()) {
String serverAddr = serverAddrsTokens.nextToken().trim();
if (serverAddr.startsWith(HTTP_PREFIX) || serverAddr.startsWith(HTTP_PREFIX)) {
if (serverAddr.startsWith(HTTP_PREFIX) || serverAddr.startsWith(HTTPS_PREFIX)) {
serverAddrs.add(serverAddr);
} else {
String[] serverAddrArr = InternetAddressUtil.splitIPPortStr(serverAddr);

View File

@ -77,7 +77,7 @@ public class YmlChangeParser extends AbstractConfigChangeParser {
}
private Map<String, Object> getFlattenedMap(Map<String, Object> source) {
Map<String, Object> result = new LinkedHashMap<String, Object>(128);
Map<String, Object> result = new LinkedHashMap<>(128);
buildFlattenedMap(result, source, null);
return result;
}

View File

@ -35,6 +35,8 @@ public class Constants {
public static final String JM_SNAPSHOT_PATH = "JM.SNAPSHOT.PATH";
public static final String NACOS_ENVS_SEARCH = "nacos.envs.search";
}
public static class Disk {

View File

@ -0,0 +1,34 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.env;
abstract class AbstractPropertySource {
/**
* get property's type.
* @return name
*/
abstract SourceType getType();
/**
* get property, if the value can not be got by the special key, the null will be returned.
* @param key special key
* @return value or null
*/
abstract String getProperty(String key);
}

View File

@ -0,0 +1,54 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.env;
import com.alibaba.nacos.common.utils.ResourceUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.net.URL;
import java.util.Properties;
class DefaultSettingPropertySource extends AbstractPropertySource {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultSettingPropertySource.class);
private static final String DEFAULT_SETTING_PATH = "classpath:nacos_default_setting.properties";
private final Properties defaultSetting = new Properties();
DefaultSettingPropertySource() {
try {
final URL resourceUrl = ResourceUtils.getResourceUrl(DEFAULT_SETTING_PATH);
final InputStream inputStream = resourceUrl.openStream();
defaultSetting.load(inputStream);
} catch (Exception e) {
LOGGER.warn("load default setting failed");
}
}
@Override
SourceType getType() {
return SourceType.DEFAULT_SETTING;
}
@Override
String getProperty(String key) {
return defaultSetting.getProperty(key);
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.env;
import java.util.Properties;
class JvmArgsPropertySource extends AbstractPropertySource {
private final Properties properties;
JvmArgsPropertySource() {
this.properties = System.getProperties();
}
@Override
SourceType getType() {
return SourceType.JVM;
}
@Override
String getProperty(String key) {
return properties.getProperty(key);
}
}

View File

@ -0,0 +1,90 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.env;
/**
* nacos env interface.
*
* @author onewe
*/
public interface NacosEnvironment {
/**
* get property, if the value can not be got by the special key, the null will be returned.
*
* @param key special key
* @return string value or null.
*/
String getProperty(String key);
/**
* get property, if the value can not be got by the special key, the default value will be returned.
* @param key special key
* @param defaultValue default value
* @return string value or default value.
*/
String getProperty(String key, String defaultValue);
/**
* get boolean, if the value can not be got by the special key, the null will be returned.
*
* @param key special key
* @return boolean value or null.
*/
Boolean getBoolean(String key);
/**
* get boolean, if the value can not be got by the special key, the default value will be returned.
* @param key special key
* @param defaultValue default value
* @return boolean value or defaultValue.
*/
Boolean getBoolean(String key, Boolean defaultValue);
/**
* get integer, if the value can not be got by the special key, the null will be returned.
*
* @param key special key
* @return integer value or null
*/
Integer getInteger(String key);
/**
* get integer, if the value can not be got by the special key, the default value will be returned.
* @param key special key
* @param defaultValue default value
* @return integer value or default value
*/
Integer getInteger(String key, Integer defaultValue);
/**
* get long, if the value can not be got by the special key, the null will be returned.
*
* @param key special key
* @return long value or null
*/
Long getLong(String key);
/**
* get long, if the value can not be got by the special key, the default value will be returned.
* @param key special key
* @param defaultValue default value
* @return long value or default value
*/
Long getLong(String key, Long defaultValue);
}

View File

@ -0,0 +1,68 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.env;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Properties;
class NacosEnvironmentFactory {
/**
* create nacos environment.
* @return NacosEnvironment's proxy object, it contains a SearchableEnvironment object.
* @see SearchableEnvironment
*/
static NacosEnvironment createEnvironment() {
return (NacosEnvironment) Proxy.newProxyInstance(NacosEnvironmentFactory.class.getClassLoader(), new Class[] {NacosEnvironment.class},
new NacosEnvironmentDelegate() {
volatile NacosEnvironment environment;
@Override
public void init(Properties properties) {
if (environment == null) {
synchronized (NacosEnvironmentFactory.class) {
if (environment == null) {
environment = new SearchableEnvironment(properties);
}
}
}
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (environment == null) {
throw new IllegalStateException(
"Nacos environment doesn't init, please call NacosEnvs#init method then try it again.");
}
return method.invoke(environment, args);
}
});
}
interface NacosEnvironmentDelegate extends InvocationHandler {
/**
* init environment.
* @param properties user customize properties
*/
void init(Properties properties);
}
}

View File

@ -0,0 +1,116 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.env;
import java.lang.reflect.Proxy;
import java.util.Properties;
/**
* environment utils.
* @author onewe
*/
public class NacosEnvs {
private static final NacosEnvironment ENVIRONMENT = NacosEnvironmentFactory.createEnvironment();
/**
* init environment.
* @param properties properties
*/
public static void init(Properties properties) {
NacosEnvironmentFactory.NacosEnvironmentDelegate warrper = (NacosEnvironmentFactory.NacosEnvironmentDelegate) Proxy.getInvocationHandler(
ENVIRONMENT);
warrper.init(properties);
}
public static String getProperty(String key, String defaultValue) {
return ENVIRONMENT.getProperty(key, defaultValue);
}
/**
* get property, if the value can not be got by the special key, the null will be returned.
*
* @param key special key
* @return string value or null.
*/
public static String getProperty(String key) {
return ENVIRONMENT.getProperty(key);
}
/**
* get boolean, if the value can not be got by the special key, the null will be returned.
*
* @param key special key
* @return boolean value or null.
*/
public static Boolean getBoolean(String key) {
return ENVIRONMENT.getBoolean(key);
}
/**
* get boolean, if the value can not be got by the special key, the default value will be returned.
*
* @param key special key
* @param defaultValue default value
* @return boolean value or defaultValue.
*/
public static Boolean getBoolean(String key, Boolean defaultValue) {
return ENVIRONMENT.getBoolean(key, defaultValue);
}
/**
* get integer, if the value can not be got by the special key, the null will be returned.
*
* @param key special key
* @return integer value or null
*/
public static Integer getInteger(String key) {
return ENVIRONMENT.getInteger(key);
}
/**
* get integer, if the value can not be got by the special key, the default value will be returned.
*
* @param key special key
* @param defaultValue default value
* @return integer value or default value
*/
public static Integer getInteger(String key, Integer defaultValue) {
return ENVIRONMENT.getInteger(key, defaultValue);
}
/**
* get long, if the value can not be got by the special key, the null will be returned.
*
* @param key special key
* @return long value or null
*/
public static Long getLong(String key) {
return ENVIRONMENT.getLong(key);
}
/**
* get long, if the value can not be got by the special key, the default value will be returned.
*
* @param key special key
* @param defaultValue default value
* @return long value or default value
*/
public static Long getLong(String key, Long defaultValue) {
return ENVIRONMENT.getLong(key, defaultValue);
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.env;
import java.util.Properties;
class PropertiesPropertySource extends AbstractPropertySource {
private final Properties properties;
PropertiesPropertySource(Properties properties) {
this.properties = properties;
}
@Override
SourceType getType() {
return SourceType.PROPERTIES;
}
@Override
String getProperty(String key) {
return properties.getProperty(key);
}
}

View File

@ -0,0 +1,119 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.env;
import com.alibaba.nacos.client.constant.Constants;
import com.alibaba.nacos.client.env.convert.CompositeConverter;
import com.alibaba.nacos.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.stream.Collectors;
class PropertySourceSearch {
private static final Logger LOGGER = LoggerFactory.getLogger(PropertySourceSearch.class);
private static final List<SourceType> DEFAULT_ORDER = Arrays.asList(SourceType.PROPERTIES, SourceType.JVM,
SourceType.SYS);
private final List<AbstractPropertySource> propertySources;
private final CompositeConverter converter;
private PropertySourceSearch(List<AbstractPropertySource> propertySources) {
this.propertySources = propertySources;
this.propertySources.add(new DefaultSettingPropertySource());
this.converter = new CompositeConverter();
}
static PropertySourceSearch build(Properties properties) {
if (properties == null) {
properties = new Properties();
}
PropertiesPropertySource customizePropertySource = new PropertiesPropertySource(properties);
JvmArgsPropertySource jvmArgsPropertySource = new JvmArgsPropertySource();
SystemEnvPropertySource systemEnvPropertySource = new SystemEnvPropertySource();
String searchPattern = jvmArgsPropertySource.getProperty(Constants.SysEnv.NACOS_ENVS_SEARCH);
if (StringUtils.isBlank(searchPattern)) {
searchPattern = systemEnvPropertySource.getProperty(Constants.SysEnv.NACOS_ENVS_SEARCH);
}
return resolve(searchPattern, customizePropertySource, jvmArgsPropertySource, systemEnvPropertySource);
}
private static PropertySourceSearch resolve(String pattern, AbstractPropertySource... propertySources) {
if (StringUtils.isBlank(pattern)) {
return createPropertySourceSearchWithDefaultOrder(propertySources);
}
try {
final SourceType sourceType = SourceType.valueOf(pattern.toUpperCase());
return createPropertySourceSearchByFirstType(sourceType, propertySources);
} catch (Exception e) {
LOGGER.error("first source type parse error, it will be use default order!");
return createPropertySourceSearchWithDefaultOrder(propertySources);
}
}
private static PropertySourceSearch createPropertySourceSearchWithDefaultOrder(AbstractPropertySource... propertySources) {
final Map<SourceType, AbstractPropertySource> sourceMap = Arrays.stream(propertySources)
.collect(Collectors.toMap(AbstractPropertySource::getType, propertySource -> propertySource));
final List<AbstractPropertySource> collect = DEFAULT_ORDER.stream().map(sourceMap::get).collect(Collectors.toList());
return new PropertySourceSearch(collect);
}
private static PropertySourceSearch createPropertySourceSearchByFirstType(SourceType firstType,
AbstractPropertySource... propertySources) {
List<SourceType> tempList = new ArrayList<>(4);
tempList.add(firstType);
final Map<SourceType, AbstractPropertySource> sourceMap = Arrays.stream(propertySources)
.collect(Collectors.toMap(AbstractPropertySource::getType, propertySource -> propertySource));
final List<AbstractPropertySource> collect = DEFAULT_ORDER.stream().filter(sourceType -> !sourceType.equals(firstType))
.collect(() -> tempList, List::add, List::addAll).stream().map(sourceMap::get)
.collect(Collectors.toList());
return new PropertySourceSearch(collect);
}
<T> Optional<T> search(String key, Class<T> targetType) {
if (targetType == null) {
throw new IllegalArgumentException("target type must be not null!");
}
for (AbstractPropertySource propertySource : propertySources) {
final String value = propertySource.getProperty(key);
if (value != null) {
if (String.class.isAssignableFrom(targetType)) {
return (Optional<T>) Optional.of(value);
}
return Optional.ofNullable(converter.convert(value, targetType));
}
}
return Optional.empty();
}
}

View File

@ -0,0 +1,74 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.env;
import java.util.Properties;
/**
* Searchable environment.
*
* @author onewe
*/
class SearchableEnvironment implements NacosEnvironment {
private final PropertySourceSearch sourceSearch;
SearchableEnvironment(Properties properties) {
this.sourceSearch = PropertySourceSearch.build(properties);
}
@Override
public String getProperty(String key) {
return getProperty(key, null);
}
@Override
public String getProperty(String key, String defaultValue) {
return sourceSearch.search(key, String.class).orElse(defaultValue);
}
@Override
public Boolean getBoolean(String key) {
return getBoolean(key, null);
}
@Override
public Boolean getBoolean(String key, Boolean defaultValue) {
return sourceSearch.search(key, Boolean.class).orElse(defaultValue);
}
@Override
public Integer getInteger(String key) {
return getInteger(key, null);
}
@Override
public Integer getInteger(String key, Integer defaultValue) {
return sourceSearch.search(key, Integer.class).orElse(defaultValue);
}
@Override
public Long getLong(String key) {
return getLong(key, null);
}
@Override
public Long getLong(String key, Long defaultValue) {
return sourceSearch.search(key, Long.class).orElse(defaultValue);
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.env;
enum SourceType {
/**
* get value from system environment.
*/
SYS,
/**
* get value from jvm args.
*/
JVM,
/**
* get value from properties.
*/
PROPERTIES,
/**
* get value from default setting.
*/
DEFAULT_SETTING
}

View File

@ -0,0 +1,84 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.env;
import java.util.Map;
class SystemEnvPropertySource extends AbstractPropertySource {
private final Map<String, String> env;
SystemEnvPropertySource() {
this.env = System.getenv();
}
@Override
SourceType getType() {
return SourceType.SYS;
}
@Override
String getProperty(String key) {
String checkedKey = checkPropertyName(key);
if (checkedKey == null) {
final String upperCaseKey = key.toUpperCase();
if (!upperCaseKey.equals(key)) {
checkedKey = checkPropertyName(upperCaseKey);
}
}
if (checkedKey == null) {
return null;
}
return env.get(checkedKey);
}
/**
* copy from https://github.com/spring-projects/spring-framework.git
* Copyright 2002-2021 the original author or authors.
* Since:
* 3.1
* Author:
* Chris Beams, Juergen Hoeller
*/
private String checkPropertyName(String name) {
// Check name as-is
if (containsKey(name)) {
return name;
}
// Check name with just dots replaced
String noDotName = name.replace('.', '_');
if (!name.equals(noDotName) && containsKey(noDotName)) {
return noDotName;
}
// Check name with just hyphens replaced
String noHyphenName = name.replace('-', '_');
if (!name.equals(noHyphenName) && containsKey(noHyphenName)) {
return noHyphenName;
}
// Check name with dots and hyphens replaced
String noDotNoHyphenName = noDotName.replace('-', '_');
if (!noDotName.equals(noDotNoHyphenName) && containsKey(noDotNoHyphenName)) {
return noDotNoHyphenName;
}
// Give up
return null;
}
private boolean containsKey(String name) {
return this.env.containsKey(name);
}
}

View File

@ -0,0 +1,28 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.env.convert;
abstract class AbstractPropertyConverter<T> {
/**
* convert property to target object.
* @param property the property gets from environments
* @return target object
*/
abstract T convert(String property);
}

View File

@ -0,0 +1,56 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.env.convert;
import com.alibaba.nacos.common.utils.StringUtils;
import java.util.HashSet;
import java.util.Set;
class BooleanConverter extends AbstractPropertyConverter<Boolean> {
private static final Set<String> TRUE_VALUES = new HashSet<>(8);
private static final Set<String> FALSE_VALUES = new HashSet<>(8);
static {
TRUE_VALUES.add("true");
TRUE_VALUES.add("on");
TRUE_VALUES.add("yes");
TRUE_VALUES.add("1");
FALSE_VALUES.add("false");
FALSE_VALUES.add("off");
FALSE_VALUES.add("no");
FALSE_VALUES.add("0");
}
@Override
Boolean convert(String property) {
if (StringUtils.isEmpty(property)) {
return null;
}
property = property.toLowerCase();
if (TRUE_VALUES.contains(property)) {
return Boolean.TRUE;
} else if (FALSE_VALUES.contains(property)) {
return Boolean.FALSE;
} else {
throw new IllegalArgumentException("Invalid boolean value '" + property + "'");
}
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.env.convert;
import java.util.HashMap;
import java.util.Map;
import java.util.MissingFormatArgumentException;
/**
* default converters.
* @author onewe
*/
public class CompositeConverter {
private final Map<Class<?>, AbstractPropertyConverter<?>> converterRegistry = new HashMap<>();
public CompositeConverter() {
converterRegistry.put(Boolean.class, new BooleanConverter());
converterRegistry.put(Integer.class, new IntegerConverter());
converterRegistry.put(Long.class, new LongConverter());
}
/**
* convert property to target type.
* @param property the property gets from environments
* @param targetClass target class object
* @param <T> target type
* @return the object of target type
*/
public <T> T convert(String property, Class<T> targetClass) {
final AbstractPropertyConverter<?> converter = converterRegistry.get(targetClass);
if (converter == null) {
throw new MissingFormatArgumentException("converter not found, can't convert from String to " + targetClass.getCanonicalName());
}
return (T) converter.convert(property);
}
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.env.convert;
import com.alibaba.nacos.common.utils.StringUtils;
class IntegerConverter extends AbstractPropertyConverter<Integer> {
@Override
Integer convert(String property) {
if (StringUtils.isEmpty(property)) {
return null;
}
try {
return Integer.valueOf(property);
} catch (Exception e) {
throw new IllegalArgumentException("Cannot convert String [" + property + "] to Integer");
}
}
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 1999-2022 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.env.convert;
import com.alibaba.nacos.common.utils.StringUtils;
class LongConverter extends AbstractPropertyConverter<Long> {
@Override
Long convert(String property) {
if (StringUtils.isEmpty(property)) {
return null;
}
try {
return Long.valueOf(property);
} catch (Exception e) {
throw new IllegalArgumentException("Cannot convert String [" + property + "] to Long");
}
}
}

View File

@ -40,11 +40,20 @@ public class LogbackNacosLogging extends AbstractNacosLogging {
@Override
public void loadConfiguration() {
LoggerContext loggerContext = loadConfigurationOnStart();
if (loggerContext.getObject(CoreConstants.RECONFIGURE_ON_CHANGE_TASK) != null) {
if (loggerContext.getObject(CoreConstants.RECONFIGURE_ON_CHANGE_TASK) != null && !hasListener(loggerContext)) {
addListener(loggerContext);
}
}
private boolean hasListener(LoggerContext loggerContext) {
for (LoggerContextListener loggerContextListener : loggerContext.getCopyOfListenerList()) {
if (loggerContextListener instanceof NacosLoggerContextListener) {
return true;
}
}
return false;
}
private LoggerContext loadConfigurationOnStart() {
String location = getLocation(NACOS_LOGBACK_LOCATION);
try {
@ -57,34 +66,36 @@ public class LogbackNacosLogging extends AbstractNacosLogging {
throw new IllegalStateException("Could not initialize Logback Nacos logging from " + location, e);
}
}
class NacosLoggerContextListener implements LoggerContextListener {
@Override
public boolean isResetResistant() {
return true;
}
@Override
public void onReset(LoggerContext context) {
loadConfigurationOnStart();
}
@Override
public void onStart(LoggerContext context) {
}
@Override
public void onStop(LoggerContext context) {
}
@Override
public void onLevelChange(Logger logger, Level level) {
}
}
private void addListener(LoggerContext loggerContext) {
loggerContext.addListener(new LoggerContextListener() {
@Override
public boolean isResetResistant() {
return true;
}
@Override
public void onReset(LoggerContext context) {
loadConfigurationOnStart();
}
@Override
public void onStart(LoggerContext context) {
}
@Override
public void onStop(LoggerContext context) {
}
@Override
public void onLevelChange(Logger logger, Level level) {
}
});
loggerContext.addListener(new NacosLoggerContextListener());
}
}

View File

@ -42,11 +42,11 @@ public class MetricsMonitor {
}
public static Gauge.Child getListenConfigCountMonitor() {
return NACOS_MONITOR.labels("naming", "listenConfigCount");
return NACOS_MONITOR.labels("config", "listenConfigCount");
}
public static Histogram.Timer getConfigRequestMonitor(String method, String url, String code) {
return NACOS_CLIENT_REQUEST_HISTOGRAM.labels("config", method, url, code).startTimer();
public static Histogram.Child getConfigRequestMonitor(String method, String url, String code) {
return NACOS_CLIENT_REQUEST_HISTOGRAM.labels("config", method, url, code);
}
public static Histogram.Child getNamingRequestMonitor(String method, String url, String code) {

View File

@ -43,6 +43,7 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.UUID;
/**
* Nacos Naming Service.
@ -71,6 +72,8 @@ public class NacosNamingService implements NamingService {
private NamingClientProxy clientProxy;
private String notifierEventScope;
public NacosNamingService(String serverList) throws NacosException {
Properties properties = new Properties();
properties.setProperty(PropertyKeyConst.SERVER_ADDR, serverList);
@ -87,11 +90,12 @@ public class NacosNamingService implements NamingService {
InitUtils.initSerialization();
InitUtils.initWebRootContext(properties);
initLogName(properties);
this.changeNotifier = new InstancesChangeNotifier();
this.notifierEventScope = UUID.randomUUID().toString();
this.changeNotifier = new InstancesChangeNotifier(this.notifierEventScope);
NotifyCenter.registerToPublisher(InstancesChangeEvent.class, 16384);
NotifyCenter.registerSubscriber(changeNotifier);
this.serviceInfoHolder = new ServiceInfoHolder(namespace, properties);
this.serviceInfoHolder = new ServiceInfoHolder(namespace, this.notifierEventScope, properties);
this.clientProxy = new NamingClientProxyDelegate(this.namespace, serviceInfoHolder, properties, changeNotifier);
}
@ -145,6 +149,13 @@ public class NacosNamingService implements NamingService {
clientProxy.registerService(serviceName, groupName, instance);
}
@Override
public void batchRegisterInstance(String serviceName, String groupName, List<Instance> instances)
throws NacosException {
NamingUtils.batchCheckInstanceIsLegal(instances);
clientProxy.batchRegisterService(serviceName, groupName, instances);
}
@Override
public void deregisterInstance(String serviceName, String ip, int port) throws NacosException {
deregisterInstance(serviceName, ip, port, Constants.DEFAULT_CLUSTER_NAME);
@ -182,23 +193,23 @@ public class NacosNamingService implements NamingService {
@Override
public List<Instance> getAllInstances(String serviceName) throws NacosException {
return getAllInstances(serviceName, new ArrayList<String>());
return getAllInstances(serviceName, new ArrayList<>());
}
@Override
public List<Instance> getAllInstances(String serviceName, String groupName) throws NacosException {
return getAllInstances(serviceName, groupName, new ArrayList<String>());
return getAllInstances(serviceName, groupName, new ArrayList<>());
}
@Override
public List<Instance> getAllInstances(String serviceName, boolean subscribe) throws NacosException {
return getAllInstances(serviceName, new ArrayList<String>(), subscribe);
return getAllInstances(serviceName, new ArrayList<>(), subscribe);
}
@Override
public List<Instance> getAllInstances(String serviceName, String groupName, boolean subscribe)
throws NacosException {
return getAllInstances(serviceName, groupName, new ArrayList<String>(), subscribe);
return getAllInstances(serviceName, groupName, new ArrayList<>(), subscribe);
}
@Override
@ -233,14 +244,14 @@ public class NacosNamingService implements NamingService {
}
List<Instance> list;
if (serviceInfo == null || CollectionUtils.isEmpty(list = serviceInfo.getHosts())) {
return new ArrayList<Instance>();
return new ArrayList<>();
}
return list;
}
@Override
public List<Instance> selectInstances(String serviceName, boolean healthy) throws NacosException {
return selectInstances(serviceName, new ArrayList<String>(), healthy);
return selectInstances(serviceName, new ArrayList<>(), healthy);
}
@Override
@ -251,13 +262,13 @@ public class NacosNamingService implements NamingService {
@Override
public List<Instance> selectInstances(String serviceName, boolean healthy, boolean subscribe)
throws NacosException {
return selectInstances(serviceName, new ArrayList<String>(), healthy, subscribe);
return selectInstances(serviceName, new ArrayList<>(), healthy, subscribe);
}
@Override
public List<Instance> selectInstances(String serviceName, String groupName, boolean healthy, boolean subscribe)
throws NacosException {
return selectInstances(serviceName, groupName, new ArrayList<String>(), healthy, subscribe);
return selectInstances(serviceName, groupName, new ArrayList<>(), healthy, subscribe);
}
@Override
@ -298,7 +309,7 @@ public class NacosNamingService implements NamingService {
private List<Instance> selectInstances(ServiceInfo serviceInfo, boolean healthy) {
List<Instance> list;
if (serviceInfo == null || CollectionUtils.isEmpty(list = serviceInfo.getHosts())) {
return new ArrayList<Instance>();
return new ArrayList<>();
}
Iterator<Instance> iterator = list.iterator();
@ -314,7 +325,7 @@ public class NacosNamingService implements NamingService {
@Override
public Instance selectOneHealthyInstance(String serviceName) throws NacosException {
return selectOneHealthyInstance(serviceName, new ArrayList<String>());
return selectOneHealthyInstance(serviceName, new ArrayList<>());
}
@Override
@ -324,13 +335,13 @@ public class NacosNamingService implements NamingService {
@Override
public Instance selectOneHealthyInstance(String serviceName, boolean subscribe) throws NacosException {
return selectOneHealthyInstance(serviceName, new ArrayList<String>(), subscribe);
return selectOneHealthyInstance(serviceName, new ArrayList<>(), subscribe);
}
@Override
public Instance selectOneHealthyInstance(String serviceName, String groupName, boolean subscribe)
throws NacosException {
return selectOneHealthyInstance(serviceName, groupName, new ArrayList<String>(), subscribe);
return selectOneHealthyInstance(serviceName, groupName, new ArrayList<>(), subscribe);
}
@Override
@ -369,12 +380,12 @@ public class NacosNamingService implements NamingService {
@Override
public void subscribe(String serviceName, EventListener listener) throws NacosException {
subscribe(serviceName, new ArrayList<String>(), listener);
subscribe(serviceName, new ArrayList<>(), listener);
}
@Override
public void subscribe(String serviceName, String groupName, EventListener listener) throws NacosException {
subscribe(serviceName, groupName, new ArrayList<String>(), listener);
subscribe(serviceName, groupName, new ArrayList<>(), listener);
}
@Override
@ -395,12 +406,12 @@ public class NacosNamingService implements NamingService {
@Override
public void unsubscribe(String serviceName, EventListener listener) throws NacosException {
unsubscribe(serviceName, new ArrayList<String>(), listener);
unsubscribe(serviceName, new ArrayList<>(), listener);
}
@Override
public void unsubscribe(String serviceName, String groupName, EventListener listener) throws NacosException {
unsubscribe(serviceName, groupName, new ArrayList<String>(), listener);
unsubscribe(serviceName, groupName, new ArrayList<>(), listener);
}
@Override

View File

@ -40,7 +40,6 @@ import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import static com.alibaba.nacos.client.utils.LogUtils.NAMING_LOGGER;
@ -60,9 +59,9 @@ public class FailoverReactor implements Closeable {
private static final String FAILOVER_MODE_PARAM = "failover-mode";
private Map<String, ServiceInfo> serviceMap = new ConcurrentHashMap<String, ServiceInfo>();
private Map<String, ServiceInfo> serviceMap = new ConcurrentHashMap<>();
private final Map<String, String> switchParams = new ConcurrentHashMap<String, String>();
private final Map<String, String> switchParams = new ConcurrentHashMap<>();
private static final long DAY_PERIOD_MINUTES = 24 * 60;
@ -76,14 +75,11 @@ public class FailoverReactor implements Closeable {
this.serviceInfoHolder = serviceInfoHolder;
this.failoverDir = cacheDir + FAILOVER_DIR;
// init executorService
this.executorService = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setDaemon(true);
thread.setName("com.alibaba.nacos.naming.failover");
return thread;
}
this.executorService = new ScheduledThreadPoolExecutor(1, r -> {
Thread thread = new Thread(r);
thread.setDaemon(true);
thread.setName("com.alibaba.nacos.naming.failover");
return thread;
});
this.init();
}
@ -98,25 +94,22 @@ public class FailoverReactor implements Closeable {
executorService.scheduleWithFixedDelay(new DiskFileWriter(), 30, DAY_PERIOD_MINUTES, TimeUnit.MINUTES);
// backup file on startup if failover directory is empty.
executorService.schedule(new Runnable() {
@Override
public void run() {
try {
File cacheDir = new File(failoverDir);
if (!cacheDir.exists() && !cacheDir.mkdirs()) {
throw new IllegalStateException("failed to create cache dir: " + failoverDir);
}
File[] files = cacheDir.listFiles();
if (files == null || files.length <= 0) {
new DiskFileWriter().run();
}
} catch (Throwable e) {
NAMING_LOGGER.error("[NA] failed to backup file on startup.", e);
executorService.schedule(() -> {
try {
File cacheDir = new File(failoverDir);
if (!cacheDir.exists() && !cacheDir.mkdirs()) {
throw new IllegalStateException("failed to create cache dir: " + failoverDir);
}
File[] files = cacheDir.listFiles();
if (files == null || files.length <= 0) {
new DiskFileWriter().run();
}
} catch (Throwable e) {
NAMING_LOGGER.error("[NA] failed to backup file on startup.", e);
}
}, 10000L, TimeUnit.MILLISECONDS);
}
@ -191,7 +184,7 @@ public class FailoverReactor implements Closeable {
@Override
public void run() {
Map<String, ServiceInfo> domMap = new HashMap<String, ServiceInfo>(16);
Map<String, ServiceInfo> domMap = new HashMap<>(16);
BufferedReader reader = null;
try {

View File

@ -37,7 +37,6 @@ import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import static com.alibaba.nacos.client.utils.LogUtils.NAMING_LOGGER;
@ -57,7 +56,7 @@ public class BeatReactor implements Closeable {
private boolean lightBeatEnabled = false;
public final Map<String, BeatInfo> dom2Beat = new ConcurrentHashMap<String, BeatInfo>();
public final Map<String, BeatInfo> dom2Beat = new ConcurrentHashMap<>();
public BeatReactor(NamingHttpClientProxy serverProxy) {
this(serverProxy, null);
@ -66,14 +65,11 @@ public class BeatReactor implements Closeable {
public BeatReactor(NamingHttpClientProxy serverProxy, Properties properties) {
this.serverProxy = serverProxy;
int threadCount = initClientBeatThreadCount(properties);
this.executorService = new ScheduledThreadPoolExecutor(threadCount, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setDaemon(true);
thread.setName("com.alibaba.nacos.naming.beat.sender");
return thread;
}
this.executorService = new ScheduledThreadPoolExecutor(threadCount, r -> {
Thread thread = new Thread(r);
thread.setDaemon(true);
thread.setName("com.alibaba.nacos.naming.beat.sender");
return thread;
});
}

View File

@ -90,7 +90,7 @@ public class DiskCache {
* @return service infos
*/
public static Map<String, ServiceInfo> read(String cacheDir) {
Map<String, ServiceInfo> domMap = new HashMap<String, ServiceInfo>(16);
Map<String, ServiceInfo> domMap = new HashMap<>(16);
BufferedReader reader = null;
try {
@ -109,7 +109,7 @@ public class DiskCache {
if (!(fileName.endsWith(Constants.SERVICE_INFO_SPLITER + "meta") || fileName
.endsWith(Constants.SERVICE_INFO_SPLITER + "special-url"))) {
ServiceInfo dom = new ServiceInfo(fileName);
List<Instance> ips = new ArrayList<Instance>();
List<Instance> ips = new ArrayList<>();
dom.setHosts(ips);
ServiceInfo newFormat = null;

View File

@ -66,7 +66,9 @@ public class ServiceInfoHolder implements Closeable {
private String cacheDir;
public ServiceInfoHolder(String namespace, Properties properties) {
private String notifierEventScope;
public ServiceInfoHolder(String namespace, String notifierEventScope, Properties properties) {
initCacheDir(namespace, properties);
if (isLoadCacheAtStart(properties)) {
this.serviceInfoMap = new ConcurrentHashMap<>(DiskCache.read(this.cacheDir));
@ -75,6 +77,7 @@ public class ServiceInfoHolder implements Closeable {
}
this.failoverReactor = new FailoverReactor(this, cacheDir);
this.pushEmptyProtection = isPushEmptyProtect(properties);
this.notifierEventScope = notifierEventScope;
}
private void initCacheDir(String namespace, Properties properties) {
@ -165,7 +168,7 @@ public class ServiceInfoHolder implements Closeable {
if (changed) {
NAMING_LOGGER.info("current ips:({}) service: {} -> {}", serviceInfo.ipCount(), serviceInfo.getKey(),
JacksonUtils.toJson(serviceInfo.getHosts()));
NotifyCenter.publishEvent(new InstancesChangeEvent(serviceInfo.getName(), serviceInfo.getGroupName(),
NotifyCenter.publishEvent(new InstancesChangeEvent(notifierEventScope, serviceInfo.getName(), serviceInfo.getGroupName(),
serviceInfo.getClusters(), serviceInfo.getHosts()));
DiskCache.write(serviceInfo, cacheDir);
}
@ -188,20 +191,20 @@ public class ServiceInfoHolder implements Closeable {
return false;
}
boolean changed = false;
Map<String, Instance> oldHostMap = new HashMap<String, Instance>(oldService.getHosts().size());
Map<String, Instance> oldHostMap = new HashMap<>(oldService.getHosts().size());
for (Instance host : oldService.getHosts()) {
oldHostMap.put(host.toInetAddr(), host);
}
Map<String, Instance> newHostMap = new HashMap<String, Instance>(newService.getHosts().size());
Map<String, Instance> newHostMap = new HashMap<>(newService.getHosts().size());
for (Instance host : newService.getHosts()) {
newHostMap.put(host.toInetAddr(), host);
}
Set<Instance> modHosts = new HashSet<Instance>();
Set<Instance> newHosts = new HashSet<Instance>();
Set<Instance> remvHosts = new HashSet<Instance>();
Set<Instance> modHosts = new HashSet<>();
Set<Instance> newHosts = new HashSet<>();
Set<Instance> remvHosts = new HashSet<>();
List<Map.Entry<String, Instance>> newServiceHosts = new ArrayList<Map.Entry<String, Instance>>(
List<Map.Entry<String, Instance>> newServiceHosts = new ArrayList<>(
newHostMap.entrySet());
for (Map.Entry<String, Instance> entry : newServiceHosts) {
Instance host = entry.getValue();
@ -222,11 +225,9 @@ public class ServiceInfoHolder implements Closeable {
if (newHostMap.containsKey(key)) {
continue;
}
if (!newHostMap.containsKey(key)) {
remvHosts.add(host);
}
//add to remove hosts
remvHosts.add(host);
}
if (newHosts.size() > 0) {

View File

@ -83,14 +83,14 @@ public class Balancer {
return null;
}
NAMING_LOGGER.debug("new Chooser");
List<Pair<Instance>> hostsWithWeight = new ArrayList<Pair<Instance>>();
List<Pair<Instance>> hostsWithWeight = new ArrayList<>();
for (Instance host : hosts) {
if (host.isHealthy()) {
hostsWithWeight.add(new Pair<Instance>(host, host.getWeight()));
}
}
NAMING_LOGGER.debug("for (Host host : hosts)");
Chooser<String, Instance> vipChooser = new Chooser<String, Instance>("www.taobao.com");
Chooser<String, Instance> vipChooser = new Chooser<>("www.taobao.com");
vipChooser.refresh(hostsWithWeight);
NAMING_LOGGER.debug("vipChooser.refresh");
return vipChooser.randomWithWeight();

View File

@ -32,7 +32,6 @@ import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import static com.alibaba.nacos.client.utils.LogUtils.NAMING_LOGGER;
@ -74,14 +73,11 @@ public class PushReceiver implements Runnable, Closeable {
} else {
this.udpSocket = new DatagramSocket(new InetSocketAddress(Integer.parseInt(udpPort)));
}
this.executorService = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setDaemon(true);
thread.setName("com.alibaba.nacos.naming.push.receiver");
return thread;
}
this.executorService = new ScheduledThreadPoolExecutor(1, r -> {
Thread thread = new Thread(r);
thread.setDaemon(true);
thread.setName("com.alibaba.nacos.naming.push.receiver");
return thread;
});
this.executorService.execute(this);

View File

@ -125,7 +125,7 @@ public class ServerListManager implements ServerListFactory, Closeable {
"Error while requesting: " + urlString + "'. Server returned: " + restResult.getCode());
}
String content = restResult.getData();
List<String> list = new ArrayList<String>();
List<String> list = new ArrayList<>();
for (String line : IoUtils.readLines(new StringReader(content))) {
if (!line.trim().isEmpty()) {
list.add(line.trim());

View File

@ -51,7 +51,7 @@ public class ServiceInfoUpdateService implements Closeable {
private static final int DEFAULT_UPDATE_CACHE_TIME_MULTIPLE = 6;
private final Map<String, ScheduledFuture<?>> futureMap = new HashMap<String, ScheduledFuture<?>>();
private final Map<String, ScheduledFuture<?>> futureMap = new HashMap<>();
private final ServiceInfoHolder serviceInfoHolder;

View File

@ -31,6 +31,8 @@ public class InstancesChangeEvent extends Event {
private static final long serialVersionUID = -8823087028212249603L;
private final String eventScope;
private final String serviceName;
private final String groupName;
@ -39,7 +41,8 @@ public class InstancesChangeEvent extends Event {
private final List<Instance> hosts;
public InstancesChangeEvent(String serviceName, String groupName, String clusters, List<Instance> hosts) {
public InstancesChangeEvent(String eventScope, String serviceName, String groupName, String clusters, List<Instance> hosts) {
this.eventScope = eventScope;
this.serviceName = serviceName;
this.groupName = groupName;
this.clusters = clusters;
@ -62,4 +65,8 @@ public class InstancesChangeEvent extends Event {
return hosts;
}
@Override
public String scope() {
return this.eventScope;
}
}

View File

@ -21,6 +21,7 @@ import com.alibaba.nacos.api.naming.listener.EventListener;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
import com.alibaba.nacos.api.naming.utils.NamingUtils;
import com.alibaba.nacos.common.JustForTest;
import com.alibaba.nacos.common.notify.Event;
import com.alibaba.nacos.common.notify.listener.Subscriber;
import com.alibaba.nacos.common.utils.CollectionUtils;
@ -29,6 +30,7 @@ import com.alibaba.nacos.common.utils.ConcurrentHashSet;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
/**
@ -39,10 +41,21 @@ import java.util.concurrent.ConcurrentHashMap;
*/
public class InstancesChangeNotifier extends Subscriber<InstancesChangeEvent> {
private final Map<String, ConcurrentHashSet<EventListener>> listenerMap = new ConcurrentHashMap<String, ConcurrentHashSet<EventListener>>();
private final String eventScope;
private final Map<String, ConcurrentHashSet<EventListener>> listenerMap = new ConcurrentHashMap<>();
private final Object lock = new Object();
@JustForTest
public InstancesChangeNotifier() {
this.eventScope = UUID.randomUUID().toString();
}
public InstancesChangeNotifier(String eventScope) {
this.eventScope = eventScope;
}
/**
* register listener.
*
@ -58,7 +71,7 @@ public class InstancesChangeNotifier extends Subscriber<InstancesChangeEvent> {
synchronized (lock) {
eventListeners = listenerMap.get(key);
if (eventListeners == null) {
eventListeners = new ConcurrentHashSet<EventListener>();
eventListeners = new ConcurrentHashSet<>();
listenerMap.put(key, eventListeners);
}
}
@ -101,7 +114,7 @@ public class InstancesChangeNotifier extends Subscriber<InstancesChangeEvent> {
}
public List<ServiceInfo> getSubscribeServices() {
List<ServiceInfo> serviceInfos = new ArrayList<ServiceInfo>();
List<ServiceInfo> serviceInfos = new ArrayList<>();
for (String key : listenerMap.keySet()) {
serviceInfos.add(ServiceInfo.fromKey(key));
}
@ -137,4 +150,8 @@ public class InstancesChangeNotifier extends Subscriber<InstancesChangeEvent> {
return InstancesChangeEvent.class;
}
@Override
public boolean scopeMatches(InstancesChangeEvent event) {
return this.eventScope.equals(event.scope());
}
}

View File

@ -24,6 +24,7 @@ import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
import com.alibaba.nacos.api.selector.AbstractSelector;
import com.alibaba.nacos.common.lifecycle.Closeable;
import java.util.List;
import java.util.Set;
/**
@ -43,6 +44,17 @@ public interface NamingClientProxy extends Closeable {
*/
void registerService(String serviceName, String groupName, Instance instance) throws NacosException;
/**
* Batch register instance to service with specified instance properties.
*
* @param serviceName service name
* @param groupName group name
* @param instances instance
* @throws NacosException nacos exception
* @since 2.1.1
*/
void batchRegisterService(String serviceName, String groupName, List<Instance> instances) throws NacosException;
/**
* Deregister instance from a service.
*

View File

@ -31,8 +31,10 @@ import com.alibaba.nacos.client.naming.remote.gprc.NamingGrpcClientProxy;
import com.alibaba.nacos.client.naming.remote.http.NamingHttpClientManager;
import com.alibaba.nacos.client.naming.remote.http.NamingHttpClientProxy;
import com.alibaba.nacos.client.security.SecurityProxy;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.alibaba.nacos.common.utils.ThreadUtils;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
@ -94,6 +96,17 @@ public class NamingClientProxyDelegate implements NamingClientProxy {
getExecuteClientProxy(instance).registerService(serviceName, groupName, instance);
}
@Override
public void batchRegisterService(String serviceName, String groupName, List<Instance> instances)
throws NacosException {
NAMING_LOGGER.info("batchRegisterInstance instances: {} ,serviceName: {} begin.", instances, serviceName);
if (CollectionUtils.isEmpty(instances)) {
NAMING_LOGGER.warn("batchRegisterInstance instances is Empty:{}", instances);
}
grpcClientProxy.batchRegisterService(serviceName, groupName, instances);
NAMING_LOGGER.info("batchRegisterInstance instances: {} ,serviceName: {} finish.", instances, serviceName);
}
@Override
public void deregisterService(String serviceName, String groupName, Instance instance) throws NacosException {
getExecuteClientProxy(instance).deregisterService(serviceName, groupName, instance);

View File

@ -24,10 +24,12 @@ import com.alibaba.nacos.api.naming.pojo.Service;
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
import com.alibaba.nacos.api.naming.remote.NamingRemoteConstants;
import com.alibaba.nacos.api.naming.remote.request.AbstractNamingRequest;
import com.alibaba.nacos.api.naming.remote.request.BatchInstanceRequest;
import com.alibaba.nacos.api.naming.remote.request.InstanceRequest;
import com.alibaba.nacos.api.naming.remote.request.ServiceListRequest;
import com.alibaba.nacos.api.naming.remote.request.ServiceQueryRequest;
import com.alibaba.nacos.api.naming.remote.request.SubscribeServiceRequest;
import com.alibaba.nacos.api.naming.remote.response.BatchInstanceResponse;
import com.alibaba.nacos.api.naming.remote.response.QueryServiceResponse;
import com.alibaba.nacos.api.naming.remote.response.ServiceListResponse;
import com.alibaba.nacos.api.naming.remote.response.SubscribeServiceResponse;
@ -50,6 +52,7 @@ import com.alibaba.nacos.common.remote.client.ServerListFactory;
import com.alibaba.nacos.common.utils.JacksonUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@ -80,7 +83,7 @@ public class NamingGrpcClientProxy extends AbstractNamingClientProxy {
this.namespaceId = namespaceId;
this.uuid = UUID.randomUUID().toString();
this.requestTimeout = Long.parseLong(properties.getProperty(CommonParams.NAMING_REQUEST_TIMEOUT, "-1"));
Map<String, String> labels = new HashMap<String, String>();
Map<String, String> labels = new HashMap<>();
labels.put(RemoteConstants.LABEL_SOURCE, RemoteConstants.LABEL_SOURCE_SDK);
labels.put(RemoteConstants.LABEL_MODULE, RemoteConstants.LABEL_MODULE_NAMING);
this.rpcClient = RpcClientFactory.createClient(uuid, ConnectionType.GRPC, labels);
@ -114,6 +117,29 @@ public class NamingGrpcClientProxy extends AbstractNamingClientProxy {
doRegisterService(serviceName, groupName, instance);
}
@Override
public void batchRegisterService(String serviceName, String groupName, List<Instance> instances)
throws NacosException {
redoService.cacheInstanceForRedo(serviceName, groupName, instances);
doBatchRegisterService(serviceName, groupName, instances);
}
/**
* Execute batch register operation.
*
* @param serviceName service name
* @param groupName group name
* @param instances instances
* @throws NacosException NacosException
*/
public void doBatchRegisterService(String serviceName, String groupName, List<Instance> instances)
throws NacosException {
BatchInstanceRequest request = new BatchInstanceRequest(namespaceId, serviceName, groupName,
NamingRemoteConstants.BATCH_REGISTER_INSTANCE, instances);
requestToServer(request, BatchInstanceResponse.class);
redoService.instanceRegistered(serviceName, groupName);
}
/**
* Execute register operation.
*
@ -199,7 +225,7 @@ public class NamingGrpcClientProxy extends AbstractNamingClientProxy {
}
}
ServiceListResponse response = requestToServer(request, ServiceListResponse.class);
ListView<String> result = new ListView<String>();
ListView<String> result = new ListView<>();
result.setCount(response.getCount());
result.setData(response.getServiceNames());
return result;
@ -284,6 +310,8 @@ public class NamingGrpcClientProxy extends AbstractNamingClientProxy {
}
NAMING_LOGGER.error("Server return unexpected response '{}', expected response should be '{}'",
response.getClass().getName(), responseClass.getName());
} catch (NacosException e) {
throw e;
} catch (Exception e) {
throw new NacosException(NacosException.SERVER_ERROR, "Request nacos server failed: ", e);
}

View File

@ -20,6 +20,7 @@ import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
import com.alibaba.nacos.api.naming.utils.NamingUtils;
import com.alibaba.nacos.client.naming.remote.gprc.NamingGrpcClientProxy;
import com.alibaba.nacos.client.naming.remote.gprc.redo.data.BatchInstanceRedoData;
import com.alibaba.nacos.client.naming.remote.gprc.redo.data.InstanceRedoData;
import com.alibaba.nacos.client.naming.remote.gprc.redo.data.SubscriberRedoData;
import com.alibaba.nacos.client.utils.LogUtils;
@ -27,6 +28,7 @@ import com.alibaba.nacos.common.executor.NameThreadFactory;
import com.alibaba.nacos.common.remote.client.ConnectionEventListener;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@ -104,6 +106,21 @@ public class NamingGrpcRedoService implements ConnectionEventListener {
}
}
/**
* Cache registered instance for redo.
*
* @param serviceName service name
* @param groupName group name
* @param instances batch registered instance
*/
public void cacheInstanceForRedo(String serviceName, String groupName, List<Instance> instances) {
String key = NamingUtils.getGroupedName(serviceName, groupName);
BatchInstanceRedoData redoData = BatchInstanceRedoData.build(serviceName, groupName, instances);
synchronized (registeredInstances) {
registeredInstances.put(key, redoData);
}
}
/**
* Instance register successfully, mark registered status as {@code true}.
*

View File

@ -18,6 +18,7 @@ package com.alibaba.nacos.client.naming.remote.gprc.redo;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.client.naming.remote.gprc.NamingGrpcClientProxy;
import com.alibaba.nacos.client.naming.remote.gprc.redo.data.BatchInstanceRedoData;
import com.alibaba.nacos.client.naming.remote.gprc.redo.data.InstanceRedoData;
import com.alibaba.nacos.client.naming.remote.gprc.redo.data.RedoData;
import com.alibaba.nacos.client.naming.remote.gprc.redo.data.SubscriberRedoData;
@ -75,7 +76,7 @@ public class RedoScheduledTask extends AbstractExecuteTask {
if (isClientDisabled()) {
return;
}
clientProxy.doRegisterService(serviceName, groupName, redoData.get());
processRegisterRedoType(redoData, serviceName, groupName);
break;
case UNREGISTER:
if (isClientDisabled()) {
@ -91,6 +92,16 @@ public class RedoScheduledTask extends AbstractExecuteTask {
}
private void processRegisterRedoType(InstanceRedoData redoData, String serviceName, String groupName) throws NacosException {
if (redoData instanceof BatchInstanceRedoData) {
// Execute Batch Register
BatchInstanceRedoData batchInstanceRedoData = (BatchInstanceRedoData) redoData;
clientProxy.doBatchRegisterService(serviceName, groupName, batchInstanceRedoData.getInstances());
return;
}
clientProxy.doRegisterService(serviceName, groupName, redoData.get());
}
private void redoForSubscribes() {
for (SubscriberRedoData each : redoService.findSubscriberRedoData()) {
try {

View File

@ -0,0 +1,57 @@
/*
* Copyright 1999-2020 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.remote.gprc.redo.data;
import com.alibaba.nacos.api.naming.pojo.Instance;
import java.util.List;
/**
* batch instance redo service.
*
* @author <a href="mailto:chenhao26@xiaomi.com">chenhao26</a>
*/
public class BatchInstanceRedoData extends InstanceRedoData {
List<Instance> instances;
public List<Instance> getInstances() {
return instances;
}
public void setInstances(List<Instance> instances) {
this.instances = instances;
}
protected BatchInstanceRedoData(String serviceName, String groupName) {
super(serviceName, groupName);
}
/**
* build BatchInstanceRedoData.
*
* @param serviceName service name
* @param groupName group name
* @param instances instances
* @return build BatchInstanceRedoData
*/
public static BatchInstanceRedoData build(String serviceName, String groupName, List<Instance> instances) {
BatchInstanceRedoData result = new BatchInstanceRedoData(serviceName, groupName);
result.setInstances(instances);
return result;
}
}

View File

@ -25,7 +25,7 @@ import com.alibaba.nacos.api.naming.pojo.Instance;
*/
public class InstanceRedoData extends RedoData<Instance> {
private InstanceRedoData(String serviceName, String groupName) {
protected InstanceRedoData(String serviceName, String groupName) {
super(serviceName, groupName);
}

Some files were not shown because too many files have changed in this diff Show More