Merge remote-tracking branch 'upstream/2.2.0' into asoc2022_issue#8461

# Conflicts:
#	config/src/main/java/com/alibaba/nacos/config/server/controller/ConfigController.java
This commit is contained in:
KomachiSion 2022-10-25 14:52:32 +08:00
commit 8410fbccf3
477 changed files with 17025 additions and 25234 deletions

View File

@ -9,6 +9,9 @@ on:
pull_request:
branches: [ develop, v1.x-develop ]
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
unix:
runs-on: ${{ matrix.os }}

View File

@ -9,6 +9,9 @@ on:
pull_request:
branches: [ develop, v1.x-develop ]
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
unix:
runs-on: ${{ matrix.os }}

View File

@ -172,7 +172,7 @@
## 0.2.1-release(Sept 28, 2018)
* FIx deregister last instance failed error.
* Fix deregister last instance failed error.
* Fix url pattern error.
* Fully integrate with and seamlessly support Spring framework, Spring Boot and Spring Cloud
* Separate nacos-api from nacos client implementation

View File

@ -83,6 +83,8 @@ For more details, see [quick-start.](https://nacos.io/en-us/docs/quick-start.htm
You can view the full documentation from the [Nacos website](https://nacos.io/en-us/docs/what-is-nacos.html).
You can also read this online eBook from the [NACOS ARCHITECTURE & PRINCIPLES](https://www.yuque.com/nacos/ebook/kbyo6n).
All the latest and long-term notice can also be found here from [Github notice issue](https://github.com/alibaba/nacos/labels/notice).
## Contributing

View File

@ -18,8 +18,8 @@ package com.alibaba.nacos.address.component;
import com.alibaba.nacos.address.constant.AddressServerConstants;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.common.utils.InternetAddressUtil;
import com.alibaba.nacos.naming.core.Instance;
import com.alibaba.nacos.common.utils.StringUtils;
import org.springframework.stereotype.Component;
@ -76,9 +76,9 @@ public class AddressServerGeneratorManager {
instance.setPort(Integer.parseInt(ipAndPort[1]));
instance.setClusterName(clusterName);
instance.setServiceName(serviceName);
instance.setTenant(Constants.DEFAULT_NAMESPACE_ID);
instance.setApp(rawProductName);
instance.setEphemeral(false);
instance.getMetadata().put("app", rawProductName);
instance.getMetadata().put("tenant", Constants.DEFAULT_NAMESPACE_ID);
instanceList.add(instance);
}
@ -99,7 +99,7 @@ public class AddressServerGeneratorManager {
* @param instanceList a instance set will generate string response to client.
* @return the result of response to client
*/
public String generateResponseIps(List<Instance> instanceList) {
public String generateResponseIps(List<com.alibaba.nacos.api.naming.pojo.Instance> instanceList) {
StringBuilder ips = new StringBuilder();
instanceList.forEach(instance -> {

View File

@ -21,13 +21,19 @@ import com.alibaba.nacos.address.component.AddressServerManager;
import com.alibaba.nacos.address.constant.AddressServerConstants;
import com.alibaba.nacos.address.misc.Loggers;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.healthcheck.AbstractHealthChecker;
import com.alibaba.nacos.api.naming.utils.NamingUtils;
import com.alibaba.nacos.common.utils.InternetAddressUtil;
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 com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.naming.core.ClusterOperator;
import com.alibaba.nacos.naming.core.InstanceOperator;
import com.alibaba.nacos.naming.core.v2.ServiceManager;
import com.alibaba.nacos.naming.core.v2.metadata.ClusterMetadata;
import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager;
import com.alibaba.nacos.naming.core.v2.metadata.ServiceMetadata;
import com.alibaba.nacos.naming.core.v2.pojo.Service;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
@ -36,6 +42,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Optional;
/**
* Address server cluster controller.
@ -47,15 +54,22 @@ import java.util.List;
@RequestMapping({AddressServerConstants.ADDRESS_SERVER_REQUEST_URL + "/nodes"})
public class AddressServerClusterController {
private final ServiceManager serviceManager;
private final InstanceOperator instanceOperator;
private final NamingMetadataManager metadataManager;
private final ClusterOperator clusterOperator;
private final AddressServerManager addressServerManager;
private final AddressServerGeneratorManager addressServerGeneratorManager;
public AddressServerClusterController(ServiceManager serviceManager, AddressServerManager addressServerManager,
public AddressServerClusterController(InstanceOperator instanceOperator, NamingMetadataManager metadataManager,
ClusterOperator clusterOperator, AddressServerManager addressServerManager,
AddressServerGeneratorManager addressServerGeneratorManager) {
this.serviceManager = serviceManager;
this.instanceOperator = instanceOperator;
this.metadataManager = metadataManager;
this.clusterOperator = clusterOperator;
this.addressServerManager = addressServerManager;
this.addressServerGeneratorManager = addressServerGeneratorManager;
}
@ -86,23 +100,13 @@ public class AddressServerClusterController {
try {
String serviceName = addressServerGeneratorManager.generateNacosServiceName(productName);
Cluster clusterObj = new Cluster();
clusterObj.setName(clusterName);
clusterObj.setHealthChecker(new AbstractHealthChecker.None());
serviceManager.createServiceIfAbsent(Constants.DEFAULT_NAMESPACE_ID, serviceName, false, clusterObj);
String[] ipArray = addressServerManager.splitIps(ips);
String checkResult = InternetAddressUtil.checkIPs(ipArray);
if (InternetAddressUtil.checkOK(checkResult)) {
List<Instance> instanceList = addressServerGeneratorManager
.generateInstancesByIps(serviceName, rawProductName, clusterName, ipArray);
for (Instance instance : instanceList) {
serviceManager.registerInstance(Constants.DEFAULT_NAMESPACE_ID, serviceName, instance);
}
Result result = registerCluster(serviceName, rawProductName, clusterName, ips);
if (InternetAddressUtil.checkOK(result.getCheckResult())) {
responseEntity = ResponseEntity
.ok("product=" + rawProductName + ",cluster=" + rawClusterName + "; put success with size="
+ instanceList.size());
+ result.getSize());
} else {
responseEntity = ResponseEntity.status(HttpStatus.BAD_REQUEST).body(checkResult);
responseEntity = ResponseEntity.status(HttpStatus.BAD_REQUEST).body(result.getCheckResult());
}
} catch (Exception e) {
responseEntity = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
@ -111,6 +115,35 @@ public class AddressServerClusterController {
return responseEntity;
}
private Result registerCluster(String serviceName, String productName, String clusterName, String ips)
throws NacosException {
String serviceWithoutGroup = NamingUtils.getServiceName(serviceName);
String groupName = NamingUtils.getGroupName(serviceName);
Service service = Service.newService(Constants.DEFAULT_NAMESPACE_ID, groupName, serviceWithoutGroup, false);
service = ServiceManager.getInstance().getSingleton(service);
if (service.isEphemeral()) {
return new Result(
String.format("Service %s is ephemeral service, can't use as address server", serviceName), 0);
}
ServiceMetadata serviceMetadata = metadataManager.getServiceMetadata(service).orElse(new ServiceMetadata());
if (!serviceMetadata.getClusters().containsKey(clusterName)) {
ClusterMetadata metadata = new ClusterMetadata();
metadata.setHealthyCheckType(AbstractHealthChecker.None.TYPE);
metadata.setHealthChecker(new AbstractHealthChecker.None());
clusterOperator.updateClusterMetadata(Constants.DEFAULT_NAMESPACE_ID, serviceName, clusterName, metadata);
}
String[] ipArray = addressServerManager.splitIps(ips);
String checkResult = InternetAddressUtil.checkIPs(ipArray);
if (InternetAddressUtil.checkOK(checkResult)) {
List<Instance> instanceList = addressServerGeneratorManager
.generateInstancesByIps(serviceName, productName, clusterName, ipArray);
for (Instance instance : instanceList) {
instanceOperator.registerInstance(Constants.DEFAULT_NAMESPACE_ID, serviceName, instance);
}
}
return new Result(checkResult, ipArray.length);
}
/**
* Delete cluster.
*
@ -134,9 +167,12 @@ public class AddressServerClusterController {
try {
String serviceName = addressServerGeneratorManager.generateNacosServiceName(productName);
Service service = serviceManager.getService(Constants.DEFAULT_NAMESPACE_ID, serviceName);
String serviceWithoutGroup = NamingUtils.getServiceName(serviceName);
String groupName = NamingUtils.getGroupName(serviceName);
Optional<com.alibaba.nacos.naming.core.v2.pojo.Service> service = com.alibaba.nacos.naming.core.v2.ServiceManager
.getInstance().getSingletonIfExist(Constants.DEFAULT_NAMESPACE_ID, groupName, serviceWithoutGroup);
if (service == null) {
if (!service.isPresent()) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("product=" + rawProductName + " not found.");
}
if (StringUtils.isBlank(ips)) {
@ -149,8 +185,9 @@ public class AddressServerClusterController {
if (InternetAddressUtil.checkOK(checkResult)) {
List<Instance> instanceList = addressServerGeneratorManager
.generateInstancesByIps(serviceName, rawProductName, clusterName, ipArray);
serviceManager.removeInstance(Constants.DEFAULT_NAMESPACE_ID, serviceName, false,
instanceList.toArray(new Instance[0]));
for (Instance each : instanceList) {
instanceOperator.removeInstance(Constants.DEFAULT_NAMESPACE_ID, serviceName, each);
}
} else {
responseEntity = ResponseEntity.status(HttpStatus.BAD_REQUEST).body(checkResult);
}
@ -162,4 +199,23 @@ public class AddressServerClusterController {
return responseEntity;
}
private class Result {
private final String checkResult;
private final int size;
public Result(String checkResult, int size) {
this.checkResult = checkResult;
this.size = size;
}
public String getCheckResult() {
return checkResult;
}
public int getSize() {
return size;
}
}
}

View File

@ -18,9 +18,15 @@ package com.alibaba.nacos.address.controller;
import com.alibaba.nacos.address.component.AddressServerGeneratorManager;
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 com.alibaba.nacos.api.naming.pojo.ServiceInfo;
import com.alibaba.nacos.api.naming.utils.NamingUtils;
import com.alibaba.nacos.naming.core.v2.ServiceManager;
import com.alibaba.nacos.naming.core.v2.index.ServiceStorage;
import com.alibaba.nacos.naming.core.v2.metadata.ClusterMetadata;
import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager;
import com.alibaba.nacos.naming.core.v2.metadata.ServiceMetadata;
import com.alibaba.nacos.naming.core.v2.pojo.Service;
import com.alibaba.nacos.naming.utils.ServiceUtil;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
@ -28,6 +34,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.Optional;
/**
* Server list controller.
*
@ -37,14 +45,17 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
public class ServerListController {
private final ServiceManager serviceManager;
private final AddressServerGeneratorManager addressServerBuilderManager;
public ServerListController(ServiceManager serviceManager,
AddressServerGeneratorManager addressServerBuilderManager) {
this.serviceManager = serviceManager;
private final NamingMetadataManager metadataManager;
private final ServiceStorage serviceStorage;
public ServerListController(AddressServerGeneratorManager addressServerBuilderManager,
NamingMetadataManager metadataManager, ServiceStorage serviceStorage) {
this.addressServerBuilderManager = addressServerBuilderManager;
this.metadataManager = metadataManager;
this.serviceStorage = serviceStorage;
}
/**
@ -59,20 +70,22 @@ public class ServerListController {
String productName = addressServerBuilderManager.generateProductName(product);
String serviceName = addressServerBuilderManager.generateNacosServiceName(productName);
Service service = serviceManager.getService(Constants.DEFAULT_NAMESPACE_ID, serviceName);
if (service == null) {
String serviceWithoutGroup = NamingUtils.getServiceName(serviceName);
String groupName = NamingUtils.getGroupName(serviceName);
Optional<Service> service = ServiceManager.getInstance()
.getSingletonIfExist(Constants.DEFAULT_NAMESPACE_ID, groupName, serviceWithoutGroup);
if (!service.isPresent()) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("product=" + product + " not found.");
}
if (!service.getClusterMap().containsKey(cluster)) {
ClusterMetadata metadata = metadataManager.getServiceMetadata(service.get()).orElse(new ServiceMetadata())
.getClusters().get(cluster);
if (null == metadata) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body("product=" + product + ",cluster=" + cluster + " not found.");
}
Cluster clusterObj = service.getClusterMap().get(cluster);
ServiceInfo serviceInfo = serviceStorage.getData(service.get());
serviceInfo = ServiceUtil.selectInstances(serviceInfo, cluster, false);
return ResponseEntity.status(HttpStatus.OK)
.body(addressServerBuilderManager.generateResponseIps(clusterObj.allIPs(false)));
.body(addressServerBuilderManager.generateResponseIps(serviceInfo.getHosts()));
}
}

View File

@ -17,7 +17,7 @@
package com.alibaba.nacos.address.component;
import com.alibaba.nacos.address.constant.AddressServerConstants;
import com.alibaba.nacos.naming.core.Instance;
import com.alibaba.nacos.api.naming.pojo.Instance;
import org.junit.Assert;
import org.junit.Test;
@ -67,7 +67,7 @@ public class AddressServerGeneratorManagerTest {
@Test
public void testGenerateResponseIps() {
final List<Instance> instanceList = new ArrayList<>();
final List<com.alibaba.nacos.api.naming.pojo.Instance> instanceList = new ArrayList<>();
Instance instance1 = new Instance();
instance1.setIp("192.168.3.1");
instance1.setPort(8848);

View File

@ -21,8 +21,12 @@ 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 com.alibaba.nacos.naming.core.ClusterOperator;
import com.alibaba.nacos.naming.core.InstanceOperator;
import com.alibaba.nacos.naming.core.v2.ServiceManager;
import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager;
import com.alibaba.nacos.naming.core.v2.pojo.Service;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -40,124 +44,94 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
public class AddressServerClusterControllerTest {
@Mock
private ServiceManager serviceManager;
private InstanceOperator instanceOperator;
@Mock
private NamingMetadataManager metadataManager;
@Mock
private ClusterOperator clusterOperator;
private MockMvc mockMvc;
@Before
public void before() {
mockMvc = MockMvcBuilders.standaloneSetup(new AddressServerClusterController(serviceManager, new AddressServerManager(),
new AddressServerGeneratorManager())).build();
mockMvc = MockMvcBuilders.standaloneSetup(
new AddressServerClusterController(instanceOperator, metadataManager, clusterOperator,
new AddressServerManager(), new AddressServerGeneratorManager())).build();
Service service = Service
.newService(Constants.DEFAULT_NAMESPACE_ID, Constants.DEFAULT_GROUP, "nacos.as.default", false);
ServiceManager.getInstance().getSingleton(service);
}
@After
public void tearDown() {
Service service = Service
.newService(Constants.DEFAULT_NAMESPACE_ID, Constants.DEFAULT_GROUP, "nacos.as.default", false);
ServiceManager.getInstance().removeSingleton(service);
}
@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());
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());
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());
Mockito.doThrow(new NacosException(500, "create service error")).when(clusterOperator)
.updateClusterMetadata(Mockito.eq(Constants.DEFAULT_NAMESPACE_ID), Mockito.eq(
Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default"),
Mockito.eq("serverList"), 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());
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());
tearDown();
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());
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());
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.doThrow(new NacosException(500, "remove service error")).when(instanceOperator)
.removeInstance(Mockito.eq(Constants.DEFAULT_NAMESPACE_ID), Mockito.eq(
Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + "nacos.as.default"),
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());
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

@ -17,25 +17,29 @@
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 com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
import com.alibaba.nacos.naming.core.v2.ServiceManager;
import com.alibaba.nacos.naming.core.v2.index.ServiceStorage;
import com.alibaba.nacos.naming.core.v2.metadata.ClusterMetadata;
import com.alibaba.nacos.naming.core.v2.metadata.NamingMetadataManager;
import com.alibaba.nacos.naming.core.v2.metadata.ServiceMetadata;
import com.alibaba.nacos.naming.core.v2.pojo.Service;
import org.junit.After;
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 java.util.Optional;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -43,68 +47,56 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
public class ServerListControllerTest {
@Mock
private ServiceManager serviceManager;
private NamingMetadataManager metadataManager;
@Mock
private ServiceStorage serviceStorage;
private Service service;
private MockMvc mockMvc;
@Before
public void before() {
this.mockMvc = MockMvcBuilders
.standaloneSetup(new ServerListController(serviceManager, new AddressServerGeneratorManager()))
.build();
this.mockMvc = MockMvcBuilders.standaloneSetup(
new ServerListController(new AddressServerGeneratorManager(), metadataManager, serviceStorage)).build();
service = Service
.newService(Constants.DEFAULT_NAMESPACE_ID, Constants.DEFAULT_GROUP, "nacos.as.default", false);
ServiceManager.getInstance().getSingleton(service);
}
@After
public void tearDown() {
ServiceManager.getInstance().removeSingleton(service);
}
@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);
final Service service = Service
.newService(Constants.DEFAULT_NAMESPACE_ID, Constants.DEFAULT_GROUP, "nacos.as.default", false);
ServiceMetadata serviceMetadata = new ServiceMetadata();
serviceMetadata.getClusters().put("serverList", new ClusterMetadata());
when(metadataManager.getServiceMetadata(service)).thenReturn(Optional.of(serviceMetadata));
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());
list.add(new Instance());
list.add(new Instance());
ServiceInfo serviceInfo = new ServiceInfo();
serviceInfo.setHosts(list);
when(serviceStorage.getData(service)).thenReturn(serviceInfo);
mockMvc.perform(get("/nacos/serverList")).andExpect(status().isOk());
}
@Test
public void testGetClusterCannotFindService() throws Exception {
mockMvc.perform(get("/default/serverList"))
.andExpect(status().isNotFound());
tearDown();
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());
mockMvc.perform(get("/nacos/serverList")).andExpect(status().isNotFound());
}
}

View File

@ -75,6 +75,8 @@ public class PropertyKeyConst {
public static final String NAMING_PUSH_EMPTY_PROTECTION = "namingPushEmptyProtection";
public static final String NAMING_ASYNC_QUERY_SUBSCRIBE_SERVICE = "namingAsyncQuerySubscribeService";
public static final String PUSH_RECEIVER_UDP_PORT = "push.receiver.udp.port";
/**

View File

@ -27,8 +27,6 @@ public interface SystemPropertyKeyConst {
String NAMING_SERVER_PORT = "nacos.naming.exposed.port";
String NAMING_WEB_CONTEXT = "nacos.naming.web.context";
/**
* In the cloud (Alibaba Cloud or other cloud vendors) environment, whether to enable namespace resolution in the
* cloud environment.

View File

@ -1,5 +1,5 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
* 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.
@ -14,29 +14,23 @@
* limitations under the License.
*/
package com.alibaba.nacos.api.config.filter;
package com.alibaba.nacos.api.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Filter Config Interface.
*
* @author Nacos
* An annotation for Nacos API v2 Controller.
* @author dongyafei
* @date 2022/7/22
*/
@Deprecated
public interface IFilterConfig {
/**
* get filter name.
*
* @return filter name
*/
String getFilterName();
/**
* Get init param.
*
* @param name parameter name
* @return param
*/
Object getInitParameter(String name);
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NacosApi {
}

View File

@ -62,13 +62,6 @@ public @interface NacosConfigurationProperties {
*/
String dataId();
/**
* set config type is yaml this method is deprecated, we support you use {@link #type()} to set config type.
*
* @return default value <code>false</code>
*/
@Deprecated boolean yaml() default false;
/**
* config style.
*

View File

@ -22,13 +22,5 @@ package com.alibaba.nacos.api.config.filter;
* @author luyanbo(RobberPhex)
*/
public abstract class AbstractConfigFilter implements IConfigFilter {
/**
* init.
*
* @param filterConfig Filter Config
*/
@Override
public void init(IFilterConfig filterConfig) {
}
}

View File

@ -30,14 +30,6 @@ import java.util.Properties;
*/
public interface IConfigFilter {
/**
* Init.
*
* @param filterConfig Filter Config
*/
@Deprecated
void init(IFilterConfig filterConfig);
/**
* Init.
*

View File

@ -0,0 +1,78 @@
/*
* 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.api.exception.api;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.utils.StringUtils;
/** Exception for open API. <BR/>
* errCode -> HTTP status code inherited from {@link NacosException} <BR/>
* errMsg -> detail error message inherited from {@link NacosException} <BR/>
* detailErrCode -> error code for api v2.0 <BR/>
* errAbstract -> abstract error message for api v2.0
* @author dongyafei
* @date 2022/7/22
*/
public class NacosApiException extends NacosException {
/**
* serialVersionUID.
*/
private static final long serialVersionUID = 2245627968556056573L;
/**
* error code for api v2.0.
*/
private int detailErrCode;
/**
* abstract error description for api v2.0.
*/
private String errAbstract;
public NacosApiException() {
}
public NacosApiException(int statusCode, ErrorCode errorCode, Throwable throwable, String message) {
super(statusCode, message, throwable);
this.detailErrCode = errorCode.getCode();
this.errAbstract = errorCode.getMsg();
}
public NacosApiException(int statusCode, ErrorCode errorCode, String message) {
super(statusCode, message);
this.detailErrCode = errorCode.getCode();
this.errAbstract = errorCode.getMsg();
}
public int getDetailErrCode() {
return detailErrCode;
}
public String getErrAbstract() {
if (!StringUtils.isBlank(this.errAbstract)) {
return this.errAbstract;
}
return Constants.NULL;
}
public void setErrAbstract(String errAbstract) {
this.errAbstract = errAbstract;
}
}

View File

@ -0,0 +1,204 @@
/*
* 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.api.model.v2;
/**
* Response Error Code.
*
* @author dongyafei
* @date 2022/7/22
*/
public enum ErrorCode {
/**
* success.
*/
SUCCESS(0, "success"),
/**
* parameter missing.
*/
PARAMETER_MISSING(10000, "parameter missing"),
/**
* access denied.
*/
ACCESS_DENIED(10001, "access denied"),
/**
* data access error.
*/
DATA_ACCESS_ERROR(10002, "data access error"),
/**
* 'tenant' parameter error.
*/
TENANT_PARAM_ERROR(20001, "'tenant' parameter error"),
/**
* parameter validate error.
*/
PARAMETER_VALIDATE_ERROR(20002, "parameter validate error"),
/**
* MediaType Error.
*/
MEDIA_TYPE_ERROR(20003, "MediaType Error"),
/**
* resource not found.
*/
RESOURCE_NOT_FOUND(20004, "resource not found"),
/**
* resource conflict.
*/
RESOURCE_CONFLICT(20005, "resource conflict"),
/**
* config listener is null.
*/
CONFIG_LISTENER_IS_NULL(20006, "config listener is null"),
/**
* config listener error.
*/
CONFIG_LISTENER_ERROR(20007, "config listener error"),
/**
* invalid dataId.
*/
INVALID_DATA_ID(20008, "invalid dataId"),
/**
* parameter mismatch.
*/
PARAMETER_MISMATCH(20009, "parameter mismatch"),
/**
* service name error.
*/
SERVICE_NAME_ERROR(21000, "service name error"),
/**
* weight error.
*/
WEIGHT_ERROR(21001, "weight error"),
/**
* instance metadata error.
*/
INSTANCE_METADATA_ERROR(21002, "instance metadata error"),
/**
* instance not found.
*/
INSTANCE_NOT_FOUND(21003, "instance not found"),
/**
* instance error.
*/
INSTANCE_ERROR(21004, "instance error"),
/**
* service metadata error.
*/
SERVICE_METADATA_ERROR(21005, "service metadata error"),
/**
* selector error.
*/
SELECTOR_ERROR(21006, "selector error"),
/**
* service already exist.
*/
SERVICE_ALREADY_EXIST(21007, "service already exist"),
/**
* service not exist.
*/
SERVICE_NOT_EXIST(21008, "service not exist"),
/**
* service delete failure.
*/
SERVICE_DELETE_FAILURE(21009, "service delete failure"),
/**
* healthy param miss.
*/
HEALTHY_PARAM_MISS(21010, "healthy param miss"),
/**
* health check still running.
*/
HEALTH_CHECK_STILL_RUNNING(21011, "health check still running"),
/**
* illegal namespace.
*/
ILLEGAL_NAMESPACE(22000, "illegal namespace"),
/**
* namespace not exist.
*/
NAMESPACE_NOT_EXIST(22001, "namespace not exist"),
/**
* namespace already exist.
*/
NAMESPACE_ALREADY_EXIST(22002, "namespace already exist"),
/**
* illegal state.
*/
ILLEGAL_STATE(23000, "illegal state"),
/**
* node info error.
*/
NODE_INFO_ERROR(23001, "node info error"),
/**
* node down failure.
*/
NODE_DOWN_FAILURE(23001, "node down failure"),
/**
* server error.
*/
SERVER_ERROR(30000, "server error");
private final Integer code;
private final String msg;
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
ErrorCode(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
}

View File

@ -0,0 +1,115 @@
/*
* 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.api.model.v2;
import java.io.Serializable;
/**
* Response Result.
*
* @author dongyafei
* @date 2022/7/12
*/
public class Result<T> implements Serializable {
private static final long serialVersionUID = 6258345442767540526L;
private final Integer code;
private final String message;
private final T data;
public Result(Integer code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
public Result() {
this(null);
}
public Result(T data) {
this(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), data);
}
public Result(Integer code, String message) {
this(code, message, null);
}
/**
* Success return with nothing.
* @param <T> data type
* @return Result
*/
public static <T> Result<T> success() {
return new Result<>();
}
/**
* Success return with data.
* @param <T> data type
* @return Result
*/
public static <T> Result<T> success(T data) {
return new Result<>(data);
}
/**
* Failed return with message and detail error information.
* @return Result
*/
public static Result<String> failure(String message) {
return Result.failure(ErrorCode.SERVER_ERROR, message);
}
/**
* Failed return with errorCode and message.
* @param <T> data type
* @return Result
*/
public static <T> Result<T> failure(ErrorCode errorCode) {
return new Result<>(errorCode.getCode(), errorCode.getMsg());
}
/**
* Failed return with errorCode, message and data.
* @param <T> data type
* @return Result
*/
public static <T> Result<T> failure(ErrorCode errorCode, T data) {
return new Result<>(errorCode.getCode(), errorCode.getMsg(), data);
}
@Override
public String toString() {
return "Result{" + "errorCode=" + code + ", message='" + message + '\'' + ", data=" + data + '}';
}
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
public T getData() {
return data;
}
}

View File

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

View File

@ -16,25 +16,18 @@
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 class BatchInstanceResponse extends InstanceResponse {
public BatchInstanceResponse() {
super();
}
public BatchInstanceResponse(String type) {
this.type = type;
}
public void setType(String type) {
this.type = type;
super(type);
}
}

View File

@ -38,4 +38,7 @@ public class InstanceResponse extends Response {
this.type = type;
}
public String getType() {
return type;
}
}

View File

@ -18,6 +18,8 @@ package com.alibaba.nacos.api.naming.utils;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.utils.StringUtils;
@ -138,11 +140,11 @@ public class NamingUtils {
public static void checkInstanceIsLegal(Instance instance) throws NacosException {
if (instance.getInstanceHeartBeatTimeOut() < instance.getInstanceHeartBeatInterval()
|| instance.getIpDeleteTimeout() < instance.getInstanceHeartBeatInterval()) {
throw new NacosException(NacosException.INVALID_PARAM,
throw new NacosApiException(NacosException.INVALID_PARAM, ErrorCode.INSTANCE_ERROR,
"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,
throw new NacosApiException(NacosException.INVALID_PARAM, ErrorCode.INSTANCE_ERROR,
String.format("Instance 'clusterName' should be characters with only 0-9a-zA-Z-. (current: %s)",
instance.getClusterName()));
}
@ -155,7 +157,7 @@ public class NamingUtils {
*/
public static void checkInstanceIsEphemeral(Instance instance) throws NacosException {
if (!instance.isEphemeral()) {
throw new NacosException(NacosException.INVALID_PARAM,
throw new NacosApiException(NacosException.INVALID_PARAM, ErrorCode.INSTANCE_ERROR,
String.format("Batch registration does not allow persistent instance registration , Instance%s", instance));
}
}

View File

@ -30,14 +30,11 @@ import java.util.Enumeration;
* @author xuanyin.zy
*/
public class NetUtils {
@Deprecated
private static final String CLIENT_NAMING_LOCAL_IP_PROPERTY = "com.alibaba.nacos.client.naming.local.ip";
private static final String CLIENT_LOCAL_IP_PROPERTY = "com.alibaba.nacos.client.local.ip";
private static final String CLIENT_LOCAL_PREFER_HOSTNAME_PROPERTY = "com.alibaba.nacos.client.local.preferHostname";
private static final String LEGAL_LOCAL_IP_PROPERTY = "java.net.preferIPv6Addresses";
private static final String DEFAULT_SOLVE_FAILED_RETURN = "resolve_failed";
@ -53,23 +50,19 @@ public class NetUtils {
if (!StringUtils.isEmpty(localIp)) {
return localIp;
}
if (System.getProperties().containsKey(CLIENT_LOCAL_IP_PROPERTY)) {
return localIp = System.getProperty(CLIENT_LOCAL_IP_PROPERTY, getAddress());
}
String ip = System.getProperty(CLIENT_NAMING_LOCAL_IP_PROPERTY, getAddress());
return localIp = ip;
localIp = getAddress();
return localIp;
}
private static String getAddress() {
InetAddress inetAddress = findFirstNonLoopbackAddress();
if (inetAddress == null) {
return DEFAULT_SOLVE_FAILED_RETURN;
}
boolean preferHost = Boolean.parseBoolean(System.getProperty(CLIENT_LOCAL_PREFER_HOSTNAME_PROPERTY));
return preferHost ? inetAddress.getHostName() : inetAddress.getHostAddress();
}
@ -91,9 +84,8 @@ public class NetUtils {
for (Enumeration<InetAddress> addrs = ifc.getInetAddresses(); addrs.hasMoreElements(); ) {
InetAddress address = addrs.nextElement();
boolean isLegalIpVersion =
Boolean.parseBoolean(System.getProperty(LEGAL_LOCAL_IP_PROPERTY))
? address instanceof Inet6Address : address instanceof Inet4Address;
boolean isLegalIpVersion = Boolean.parseBoolean(System.getProperty(LEGAL_LOCAL_IP_PROPERTY))
? address instanceof Inet6Address : address instanceof Inet4Address;
if (isLegalIpVersion && !address.isLoopbackAddress()) {
result = address;
}

View File

@ -54,7 +54,7 @@ public class NamingUtilsTest {
NamingUtils.checkInstanceIsLegal(instance);
assertTrue(false);
} catch (Exception e) {
assertTrue(NacosException.class.equals(e.getClass()));
assertTrue(e instanceof NacosException);
assertEquals(
"Instance 'clusterName' should be characters with only 0-9a-zA-Z-. (current: cluster1,cluster2)",
e.getMessage());
@ -75,7 +75,7 @@ public class NamingUtilsTest {
NamingUtils.checkInstanceIsLegal(instance);
assertTrue(false);
} catch (Exception e) {
assertTrue(NacosException.class.equals(e.getClass()));
assertTrue(e instanceof NacosException);
assertEquals(
"Instance 'heart beat interval' must less than 'heart beat timeout' and 'ip delete timeout'.",
e.getMessage());
@ -98,7 +98,7 @@ public class NamingUtilsTest {
NamingUtils.batchCheckInstanceIsLegal(instanceList);
assertTrue(false);
} catch (Exception e) {
assertTrue(NacosException.class.equals(e.getClass()));
assertTrue(e instanceof NacosException);
assertEquals(
"Instance 'clusterName' should be characters with only 0-9a-zA-Z-. (current: cluster1,cluster2)",
e.getMessage());
@ -124,7 +124,7 @@ public class NamingUtilsTest {
NamingUtils.batchCheckInstanceIsLegal(instanceList);
assertTrue(false);
} catch (Exception e) {
assertTrue(NacosException.class.equals(e.getClass()));
assertTrue(e instanceof NacosException);
assertEquals(
"Instance 'heart beat interval' must less than 'heart beat timeout' and 'ip delete timeout'.",
e.getMessage());
@ -166,4 +166,4 @@ public class NamingUtilsTest {
String str2 = "123456";
assertTrue(NamingUtils.isNumber(str2));
}
}
}

View File

@ -34,7 +34,6 @@ public class NetUtilsTest {
field.setAccessible(true);
field.set(null, "");
System.clearProperty("com.alibaba.nacos.client.local.ip");
System.clearProperty("com.alibaba.nacos.client.naming.local.ip");
System.clearProperty("com.alibaba.nacos.client.local.preferHostname");
}
@ -45,12 +44,6 @@ public class NetUtilsTest {
assertEquals("10.2.8.8", NetUtils.localIP());
}
@Test
public void testCompatibleLocalIP() {
System.setProperty("com.alibaba.nacos.client.naming.local.ip", "10.2.7.8");
assertEquals("10.2.7.8", NetUtils.localIP());
}
@Test
public void testPreferHostname() throws Exception {
Class<?> clazz = Class.forName("com.alibaba.nacos.api.utils.NetUtils");
@ -63,4 +56,4 @@ public class NetUtilsTest {
assertEquals(hostname, NetUtils.localIP());
}
}
}

View File

@ -145,7 +145,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<version>3.2.4</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
@ -159,25 +159,56 @@
<keepDependenciesWithProvidedScope>false</keepDependenciesWithProvidedScope>
<promoteTransitiveDependencies>true</promoteTransitiveDependencies>
<createDependencyReducedPom>false</createDependencyReducedPom>
<minimizeJar>false</minimizeJar>
<minimizeJar>true</minimizeJar>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
<filter>
<artifact>io.grpc:grpc-netty-shaded</artifact>
<excludes>
<exclude>
META-INF/native/*.*
</exclude>
</excludes>
</filter>
<filter>
<artifact>com.alibaba.nacos:nacos-api</artifact>
<includes>
<include>
com/alibaba/nacos/api/**/**
</include>
</includes>
</filter>
</filters>
<createSourcesJar>true</createSourcesJar>
<shadeSourcesContent>true</shadeSourcesContent>
<artifactSet>
<includes>
<include>io.grpc:*</include>
<include>io.opencensus:*</include>
<include>io.perfmark:*</include>
<include>com.google.guava:guava</include>
<include>com.google.guava:failureaccess</include>
<include>com.google.errorprone:error_prone_annotations</include>
<include>com.google.j2objc:j2objc-annotations</include>
<include>com.google.code.gson:gson</include>
<include>com.google.protobuf:protobuf-java</include>
<include>com.alibaba.nacos:nacos-api</include>
<include>com.alibaba.nacos:nacos-common</include>
<include>org.checkerframework:checker-qual</include>
<include>org.conscrypt:conscrypt-openjdk</include>
<include>org.mortbay.jetty.alpn:alpn-boot</include>
<include>org.eclipse.jetty.npn:npn-api</include>
<include>org.reflections:reflections</include>
<include>com.google.guava:guava</include>
<include>io.grpc:*</include>
<include>io.opencensus:*</include>
<include>org.javassist:*</include>
<include>io.perfmark:perfmark-api</include>
<include>com.google.*:*</include>
<include>javax.annotation:javax.annotation-api</include>
<include>org.checkerframework:*</include>
<include>org.codehaus.mojo:*</include>
</includes>
</artifactSet>
<relocations>
@ -202,6 +233,12 @@
<pattern>com.google</pattern>
<shadedPattern>com.alibaba.nacos.shaded.com.google</shadedPattern>
</relocation>
<relocation>
<pattern>javax.annotation</pattern>
<shadedPattern>com.alibaba.nacos.shaded.javax.annotation</shadedPattern>
</relocation>
<relocation>
<pattern>io.perfmark</pattern>
<shadedPattern>com.alibaba.nacos.shaded.io.perfmark</shadedPattern>
@ -227,7 +264,6 @@
<shadedPattern>com.alibaba.nacos.shaded.org.example</shadedPattern>
</relocation>
</relocations>
<transformers>
<transformer
@ -240,6 +276,21 @@
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>pure-jar</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>pure</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
@ -250,7 +301,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<version>3.2.4</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
@ -264,29 +315,60 @@
<keepDependenciesWithProvidedScope>false</keepDependenciesWithProvidedScope>
<promoteTransitiveDependencies>true</promoteTransitiveDependencies>
<createDependencyReducedPom>false</createDependencyReducedPom>
<minimizeJar>false</minimizeJar>
<minimizeJar>true</minimizeJar>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
<filter>
<artifact>io.grpc:grpc-netty-shaded</artifact>
<excludes>
<exclude>
META-INF/native/*.*
</exclude>
</excludes>
</filter>
<filter>
<artifact>com.alibaba.nacos:nacos-api</artifact>
<includes>
<include>
com/alibaba/nacos/api/**/**
</include>
</includes>
</filter>
</filters>
<createSourcesJar>true</createSourcesJar>
<shadeSourcesContent>true</shadeSourcesContent>
<artifactSet>
<includes>
<include>io.grpc:*</include>
<include>io.opencensus:*</include>
<include>io.perfmark:*</include>
<include>com.google.guava:guava</include>
<include>com.google.guava:failureaccess</include>
<include>com.google.errorprone:error_prone_annotations</include>
<include>com.google.j2objc:j2objc-annotations</include>
<include>com.google.code.gson:gson</include>
<include>com.google.protobuf:protobuf-java</include>
<include>com.alibaba.nacos:nacos-api</include>
<include>com.alibaba.nacos:nacos-common</include>
<include>org.checkerframework:checker-qual</include>
<include>org.conscrypt:conscrypt-openjdk</include>
<include>org.mortbay.jetty.alpn:alpn-boot</include>
<include>org.eclipse.jetty.npn:npn-api</include>
<include>org.reflections:reflections</include>
<include>com.google.guava:guava</include>
<include>io.grpc:*</include>
<include>io.opencensus:*</include>
<include>org.javassist:*</include>
<include>io.perfmark:perfmark-api</include>
<include>com.google.*:*</include>
<include>javax.annotation:javax.annotation-api</include>
<include>org.checkerframework:*</include>
<include>org.codehaus.mojo:*</include>
</includes>
</artifactSet>
<relocations>
<relocation>
<pattern>io.grpc</pattern>
<shadedPattern>com.alibaba.nacos.shaded.io.grpc</shadedPattern>
@ -302,11 +384,17 @@
<include>io.grpc.netty.shaded.io.grpc.netty.*</include>
</includes>
</relocation>
<relocation>
<pattern>com.google</pattern>
<shadedPattern>com.alibaba.nacos.shaded.com.google</shadedPattern>
</relocation>
<relocation>
<pattern>javax.annotation</pattern>
<shadedPattern>com.alibaba.nacos.shaded.javax.annotation</shadedPattern>
</relocation>
<relocation>
<pattern>io.perfmark</pattern>
<shadedPattern>com.alibaba.nacos.shaded.io.perfmark</shadedPattern>
@ -331,20 +419,34 @@
<pattern>org.example</pattern>
<shadedPattern>com.alibaba.nacos.shaded.org.example</shadedPattern>
</relocation>
</relocations>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"/>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>pure-jar</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>pure</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>

View File

@ -126,25 +126,4 @@ public final class CredentialService implements SpasCredentialLoader {
public void registerCredentialListener(CredentialListener listener) {
this.listener = listener;
}
@Deprecated
public void setAccessKey(String accessKey) {
credentials.setAccessKey(accessKey);
}
@Deprecated
public void setSecretKey(String secretKey) {
credentials.setSecretKey(secretKey);
}
@Deprecated
public String getAccessKey() {
return credentials.getAccessKey();
}
@Deprecated
public String getSecretKey() {
return credentials.getSecretKey();
}
}

View File

@ -275,6 +275,7 @@ public class ServerHttpAgent implements HttpAgent {
String className = this.getClass().getName();
LOGGER.info("{} do shutdown begin", className);
ConfigHttpClientManager.getInstance().shutdown();
serverListMgr.shutdown();
LOGGER.info("{} do shutdown stop", className);
}
}

View File

@ -111,6 +111,11 @@ public class CacheData {
*/
private volatile boolean isSyncWithServer = false;
/**
* if is cache data is discard,need to remove.
*/
private volatile boolean isDiscard = false;
private String type;
public boolean isInitializing() {
@ -402,6 +407,14 @@ public class CacheData {
isSyncWithServer = syncWithServer;
}
public boolean isDiscard() {
return isDiscard;
}
public void setDiscard(boolean discard) {
isDiscard = discard;
}
public CacheData(ConfigFilterChainManager configFilterChainManager, String name, String dataId, String group) {
this(configFilterChainManager, name, dataId, group, TenantUtil.getUserTenantForAcm());
}

View File

@ -126,11 +126,11 @@ public class ClientWorker implements Closeable {
private int taskPenaltyTime;
private boolean enableRemoteSyncConfig = false;
private static final int MIN_THREAD_NUM = 2;
private static final int THREAD_MULTIPLE = 1;
/**
* Add listeners for data.
*
@ -146,6 +146,7 @@ public class ClientWorker implements Closeable {
for (Listener listener : listeners) {
cache.addListener(listener);
}
cache.setDiscard(false);
cache.setSyncWithServer(false);
agent.notifyListenConfig();
@ -169,6 +170,7 @@ public class ClientWorker implements Closeable {
for (Listener listener : listeners) {
cache.addListener(listener);
}
cache.setDiscard(false);
cache.setSyncWithServer(false);
agent.notifyListenConfig();
}
@ -196,6 +198,7 @@ public class ClientWorker implements Closeable {
for (Listener listener : listeners) {
cache.addListener(listener);
}
cache.setDiscard(false);
cache.setSyncWithServer(false);
agent.notifyListenConfig();
}
@ -217,6 +220,7 @@ public class ClientWorker implements Closeable {
cache.removeListener(listener);
if (cache.getListeners().isEmpty()) {
cache.setSyncWithServer(false);
cache.setDiscard(true);
agent.removeCache(dataId, group);
}
}
@ -240,6 +244,7 @@ public class ClientWorker implements Closeable {
cache.removeListener(listener);
if (cache.getListeners().isEmpty()) {
cache.setSyncWithServer(false);
cache.setDiscard(true);
agent.removeCache(dataId, group);
}
}
@ -425,8 +430,8 @@ public class ClientWorker implements Closeable {
}
private void refreshContentAndCheck(String groupKey, boolean notify) {
if (cacheMap.get() != null && cacheMap.get().containsKey(groupKey)) {
CacheData cache = cacheMap.get().get(groupKey);
CacheData cache = cacheMap.get().get(groupKey);
if (cache != null) {
refreshContentAndCheck(cache, notify);
}
}
@ -696,7 +701,7 @@ public class ClientWorker implements Closeable {
continue;
}
executeConfigListen();
} catch (Exception e) {
} catch (Throwable e) {
LOGGER.error("[ rpc listen execute ] [rpc listen] exception", e);
}
}
@ -733,7 +738,7 @@ public class ClientWorker implements Closeable {
}
}
if (!CollectionUtils.isEmpty(cache.getListeners())) {
if (!cache.isDiscard()) {
//get listen config
if (!cache.isUseLocalConfigInfo()) {
List<CacheData> cacheDatas = listenCachesMap.get(String.valueOf(cache.getTaskId()));
@ -744,7 +749,7 @@ public class ClientWorker implements Closeable {
cacheDatas.add(cache);
}
} else if (CollectionUtils.isEmpty(cache.getListeners())) {
} else if (cache.isDiscard()) {
if (!cache.isUseLocalConfigInfo()) {
List<CacheData> cacheDatas = removeListenCachesMap.get(String.valueOf(cache.getTaskId()));
@ -779,7 +784,7 @@ public class ClientWorker implements Closeable {
RpcClient rpcClient = ensureRpcClient(taskId);
ConfigChangeBatchListenResponse configChangeBatchListenResponse = (ConfigChangeBatchListenResponse) requestProxy(
rpcClient, configChangeListenRequest);
if (configChangeBatchListenResponse != null && configChangeBatchListenResponse.isSuccess()) {
if (configChangeBatchListenResponse.isSuccess()) {
Set<String> changeKeys = new HashSet<>();
//handle changed keys,notify listener
@ -807,8 +812,8 @@ public class ClientWorker implements Closeable {
if (!cacheData.getListeners().isEmpty()) {
Long previousTimesStamp = timestampMap.get(groupKey);
if (previousTimesStamp != null && !cacheData.getLastModifiedTs().compareAndSet(previousTimesStamp,
System.currentTimeMillis())) {
if (previousTimesStamp != null && !cacheData.getLastModifiedTs()
.compareAndSet(previousTimesStamp, System.currentTimeMillis())) {
continue;
}
cacheData.setSyncWithServer(true);
@ -844,7 +849,7 @@ public class ClientWorker implements Closeable {
if (removeSuccess) {
for (CacheData cacheData : removeListenCaches) {
synchronized (cacheData) {
if (cacheData.getListeners().isEmpty()) {
if (cacheData.isDiscard()) {
ClientWorker.this
.removeCache(cacheData.dataId, cacheData.group, cacheData.tenant);
}
@ -979,8 +984,8 @@ public class ClientWorker implements Closeable {
LOGGER.error("[{}] [sub-server-error] dataId={}, group={}, tenant={}, code={}", this.getName(), dataId,
group, tenant, response);
throw new NacosException(response.getErrorCode(),
"http error, code=" + response.getErrorCode() + ",msg=" + response.getMessage() + ",dataId=" + dataId + ",group=" + group
+ ",tenant=" + tenant);
"http error, code=" + response.getErrorCode() + ",msg=" + response.getMessage() + ",dataId="
+ dataId + ",group=" + group + ",tenant=" + tenant);
}
}
@ -1012,20 +1017,20 @@ public class ClientWorker implements Closeable {
if (request instanceof ConfigQueryRequest) {
String tenant = ((ConfigQueryRequest) request).getTenant();
String group = ((ConfigQueryRequest) request).getGroup();
String dataId = ((ConfigQueryRequest) request).getGroup();
String dataId = ((ConfigQueryRequest) request).getDataId();
return buildResource(tenant, group, dataId);
}
if (request instanceof ConfigPublishRequest) {
String tenant = ((ConfigPublishRequest) request).getTenant();
String group = ((ConfigPublishRequest) request).getGroup();
String dataId = ((ConfigPublishRequest) request).getGroup();
String dataId = ((ConfigPublishRequest) request).getDataId();
return buildResource(tenant, group, dataId);
}
if (request instanceof ConfigRemoveRequest) {
String tenant = ((ConfigRemoveRequest) request).getTenant();
String group = ((ConfigRemoveRequest) request).getGroup();
String dataId = ((ConfigRemoveRequest) request).getGroup();
String dataId = ((ConfigRemoveRequest) request).getDataId();
return buildResource(tenant, group, dataId);
}
return RequestResource.configBuilder().build();
@ -1059,7 +1064,7 @@ public class ClientWorker implements Closeable {
}
} catch (Exception e) {
LOGGER.warn("[{}] [publish-single] error, dataId={}, group={}, tenant={}, code={}, msg={}",
this.getName(), dataId, group, tenant, "unkonw", e.getMessage());
this.getName(), dataId, group, tenant, "unknown", e.getMessage());
return false;
}
}

View File

@ -35,7 +35,7 @@ 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 final String NACOS_ENV_FIRST = "nacos.env.first";
}

View File

@ -16,6 +16,8 @@
package com.alibaba.nacos.client.env;
import java.util.Properties;
abstract class AbstractPropertySource {
/**
@ -31,4 +33,17 @@ abstract class AbstractPropertySource {
*/
abstract String getProperty(String key);
/**
* Tests if the specified object is a key in this propertySource.
* @param key key possible key
* @return true if and only if the specified object is a key in this propertySource, false otherwise.
*/
abstract boolean containsKey(String key);
/**
* to properties.
* @return properties
*/
abstract Properties asProperties();
}

View File

@ -21,7 +21,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.net.URL;
import java.util.Properties;
class DefaultSettingPropertySource extends AbstractPropertySource {
@ -33,12 +32,10 @@ class DefaultSettingPropertySource extends AbstractPropertySource {
private final Properties defaultSetting = new Properties();
DefaultSettingPropertySource() {
try {
final URL resourceUrl = ResourceUtils.getResourceUrl(DEFAULT_SETTING_PATH);
final InputStream inputStream = resourceUrl.openStream();
try (final InputStream inputStream = ResourceUtils.getResourceUrl(DEFAULT_SETTING_PATH).openStream()) {
defaultSetting.load(inputStream);
} catch (Exception e) {
LOGGER.warn("load default setting failed");
LOGGER.error("load default setting failed", e);
}
}
@ -51,4 +48,16 @@ class DefaultSettingPropertySource extends AbstractPropertySource {
String getProperty(String key) {
return defaultSetting.getProperty(key);
}
@Override
boolean containsKey(String key) {
return defaultSetting.containsKey(key);
}
@Override
Properties asProperties() {
Properties properties = new Properties();
properties.putAll(defaultSetting);
return properties;
}
}

View File

@ -35,4 +35,16 @@ class JvmArgsPropertySource extends AbstractPropertySource {
String getProperty(String key) {
return properties.getProperty(key);
}
@Override
boolean containsKey(String key) {
return properties.containsKey(key);
}
@Override
Properties asProperties() {
Properties properties = new Properties();
properties.putAll(this.properties);
return properties;
}
}

View File

@ -16,12 +16,27 @@
package com.alibaba.nacos.client.env;
import java.util.Properties;
/**
* nacos env interface.
*
* NacosClientProperties interface.
* include all the properties from jvm args, system environment, default setting.
* more details you can see https://github.com/alibaba/nacos/issues/8622
* @author onewe
*/
public interface NacosEnvironment {
public interface NacosClientProperties {
/**
* all the NacosClientProperties object must be created by PROTOTYPE,
* so child NacosClientProperties can read properties from the PROTOTYPE.
* it looks like this:
* |-PROTOTYPE----------------> ip=127.0.0.1
* |---|-child1---------------> port=6379
* if you search key called "port" from child1, certainly you will get 6379
* if you search key called "ip" from child1, you will get 127.0.0.1.
* because the child can read properties from parent NacosClientProperties
*/
NacosClientProperties PROTOTYPE = SearchableProperties.INSTANCE;
/**
* get property, if the value can not be got by the special key, the null will be returned.
@ -87,4 +102,42 @@ public interface NacosEnvironment {
*/
Long getLong(String key, Long defaultValue);
/**
* set property.
* @param key key
* @param value value
*/
void setProperty(String key, String value);
/**
* add properties.
* @param properties properties
*/
void addProperties(Properties properties);
/**
* Tests if the specified object is a key in this NacosClientProperties.
* @param key key possible key
* @return true if and only if the specified object is a key in this NacosClientProperties, false otherwise.
*/
boolean containsKey(String key);
/**
* get properties from NacosClientProperties.
* @return properties
*/
Properties asProperties();
/**
* create a new NacosClientProperties which scope is itself.
* @return NacosClientProperties
*/
NacosClientProperties derive();
/**
* create a new NacosClientProperties from NacosClientProperties#PROTOTYPE and init.
* @param properties properties
* @return NacosClientProperties
*/
NacosClientProperties derive(Properties properties);
}

View File

@ -1,68 +0,0 @@
/*
* 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

@ -1,116 +0,0 @@
/*
* 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

@ -16,14 +16,23 @@
package com.alibaba.nacos.client.env;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Properties;
class PropertiesPropertySource extends AbstractPropertySource {
private final Properties properties;
private final Properties properties = new Properties();
PropertiesPropertySource(Properties properties) {
this.properties = properties;
private final PropertiesPropertySource parent;
PropertiesPropertySource() {
this.parent = null;
}
PropertiesPropertySource(PropertiesPropertySource parent) {
this.parent = parent;
}
@Override
@ -33,6 +42,67 @@ class PropertiesPropertySource extends AbstractPropertySource {
@Override
String getProperty(String key) {
return properties.getProperty(key);
return getProperty(this, key);
}
private String getProperty(PropertiesPropertySource propertiesPropertySource, String key) {
final String value = propertiesPropertySource.properties.getProperty(key);
if (value != null) {
return value;
}
final PropertiesPropertySource parent = propertiesPropertySource.parent;
if (parent == null) {
return null;
}
return getProperty(parent, key);
}
@Override
boolean containsKey(String key) {
return containsKey(this, key);
}
boolean containsKey(PropertiesPropertySource propertiesPropertySource, String key) {
final boolean exist = propertiesPropertySource.properties.containsKey(key);
if (exist) {
return true;
}
final PropertiesPropertySource parent = propertiesPropertySource.parent;
if (parent == null) {
return false;
}
return containsKey(parent, key);
}
@Override
Properties asProperties() {
List<Properties> propertiesList = new ArrayList<>(8);
propertiesList = lookForProperties(this, propertiesList);
Properties ret = new Properties();
final ListIterator<Properties> iterator = propertiesList.listIterator(propertiesList.size());
while (iterator.hasPrevious()) {
final Properties properties = iterator.previous();
ret.putAll(properties);
}
return ret;
}
List<Properties> lookForProperties(PropertiesPropertySource propertiesPropertySource, List<Properties> propertiesList) {
propertiesList.add(propertiesPropertySource.properties);
final PropertiesPropertySource parent = propertiesPropertySource.parent;
if (parent == null) {
return propertiesList;
}
return lookForProperties(parent, propertiesList);
}
synchronized void setProperty(String key, String value) {
properties.setProperty(key, value);
}
synchronized void addProperties(Properties source) {
properties.putAll(source);
}
}

View File

@ -1,119 +0,0 @@
/*
* 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

@ -1,74 +0,0 @@
/*
* 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,236 @@
/*
* 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.ListIterator;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Properties;
import java.util.stream.Collectors;
/**
* Searchable NacosClientProperties.
* the SearchableProperties that it can be specified search order by
* nacos.env.first
* @author onewe
*/
class SearchableProperties implements NacosClientProperties {
private static final Logger LOGGER = LoggerFactory.getLogger(SearchableProperties.class);
private static final JvmArgsPropertySource JVM_ARGS_PROPERTY_SOURCE = new JvmArgsPropertySource();
private static final SystemEnvPropertySource SYSTEM_ENV_PROPERTY_SOURCE = new SystemEnvPropertySource();
private static final DefaultSettingPropertySource DEFAULT_SETTING_PROPERTY_SOURCE = new DefaultSettingPropertySource();
private static final List<SourceType> DEFAULT_ORDER = Arrays.asList(SourceType.PROPERTIES, SourceType.JVM,
SourceType.ENV, SourceType.DEFAULT_SETTING);
private static final CompositeConverter CONVERTER = new CompositeConverter();
static final SearchableProperties INSTANCE = new SearchableProperties();
private final List<AbstractPropertySource> propertySources;
private final PropertiesPropertySource propertiesPropertySource;
private SearchableProperties() {
this(new PropertiesPropertySource());
}
private SearchableProperties(PropertiesPropertySource propertiesPropertySource) {
this.propertiesPropertySource = propertiesPropertySource;
this.propertySources = build(propertiesPropertySource,
JVM_ARGS_PROPERTY_SOURCE, SYSTEM_ENV_PROPERTY_SOURCE, DEFAULT_SETTING_PROPERTY_SOURCE);
}
@Override
public String getProperty(String key) {
return getProperty(key, null);
}
@Override
public String getProperty(String key, String defaultValue) {
return this.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 this.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 this.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 this.search(key, Long.class).orElse(defaultValue);
}
@Override
public void setProperty(String key, String value) {
propertiesPropertySource.setProperty(key, value);
}
@Override
public void addProperties(Properties properties) {
propertiesPropertySource.addProperties(properties);
}
@Override
public Properties asProperties() {
Properties properties = new Properties();
final ListIterator<AbstractPropertySource> iterator = propertySources.listIterator(
propertySources.size());
while (iterator.hasPrevious()) {
final AbstractPropertySource previous = iterator.previous();
properties.putAll(previous.asProperties());
}
return properties;
}
@Override
public boolean containsKey(String key) {
for (AbstractPropertySource propertySource : propertySources) {
final boolean containing = propertySource.containsKey(key);
if (containing) {
return true;
}
}
return false;
}
private <T> Optional<T> search(String key, Class<T> targetType) {
if (targetType == null) {
throw new IllegalArgumentException("target type must not be null!");
}
for (AbstractPropertySource propertySource : propertySources) {
final String value = propertySource.getProperty(key);
if (value != null) {
if (String.class.isAssignableFrom(targetType)) {
try {
return (Optional<T>) Optional.of(value);
} catch (Exception e) {
LOGGER.error("target type convert error", e);
return Optional.empty();
}
}
return Optional.ofNullable(CONVERTER.convert(value, targetType));
}
}
return Optional.empty();
}
private List<AbstractPropertySource> build(AbstractPropertySource... propertySources) {
String firstEnv = JVM_ARGS_PROPERTY_SOURCE.getProperty(Constants.SysEnv.NACOS_ENV_FIRST);
if (StringUtils.isBlank(firstEnv)) {
firstEnv = SYSTEM_ENV_PROPERTY_SOURCE.getProperty(Constants.SysEnv.NACOS_ENV_FIRST);
}
if (StringUtils.isBlank(firstEnv)) {
return sortPropertySourceDefaultOrder(propertySources);
}
try {
final SourceType sourceType = SourceType.valueOf(firstEnv.toUpperCase());
if (SourceType.DEFAULT_SETTING.equals(sourceType) || SourceType.PROPERTIES.equals(sourceType)) {
return sortPropertySourceDefaultOrder(propertySources);
}
return sortPropertySource(sourceType, propertySources);
} catch (Exception e) {
LOGGER.error("first source type parse error, it will be used default order!", e);
return sortPropertySourceDefaultOrder(propertySources);
}
}
private List<AbstractPropertySource> sortPropertySourceDefaultOrder(
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());
LOGGER.info("properties search order:PROPERTIES->JVM->ENV->DEFAULT_SETTING");
return collect;
}
private List<AbstractPropertySource> sortPropertySource(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).filter(Objects::nonNull).collect(Collectors.toList());
StringBuilder orderInfo = new StringBuilder("properties search order:");
for (int i = 0; i < collect.size(); i++) {
final AbstractPropertySource abstractPropertySource = collect.get(i);
orderInfo.append(abstractPropertySource.getType().toString());
if (i < collect.size() - 1) {
orderInfo.append("->");
}
}
LOGGER.info(orderInfo.toString());
return collect;
}
@Override
public NacosClientProperties derive() {
return new SearchableProperties(new PropertiesPropertySource(this.propertiesPropertySource));
}
@Override
public NacosClientProperties derive(Properties properties) {
final NacosClientProperties nacosClientProperties = this.derive();
nacosClientProperties.addProperties(properties);
return nacosClientProperties;
}
}

View File

@ -18,17 +18,17 @@ package com.alibaba.nacos.client.env;
enum SourceType {
/**
* get value from system environment.
* get value from properties.
*/
SYS,
PROPERTIES,
/**
* get value from jvm args.
*/
JVM,
/**
* get value from properties.
* get value from system environment.
*/
PROPERTIES,
ENV,
/**
* get value from default setting.
*/

View File

@ -17,18 +17,15 @@
package com.alibaba.nacos.client.env;
import java.util.Map;
import java.util.Properties;
class SystemEnvPropertySource extends AbstractPropertySource {
private final Map<String, String> env;
SystemEnvPropertySource() {
this.env = System.getenv();
}
private final Map<String, String> env = System.getenv();
@Override
SourceType getType() {
return SourceType.SYS;
return SourceType.ENV;
}
@Override
@ -78,7 +75,15 @@ class SystemEnvPropertySource extends AbstractPropertySource {
return null;
}
private boolean containsKey(String name) {
@Override
boolean containsKey(String name) {
return this.env.containsKey(name);
}
@Override
Properties asProperties() {
Properties properties = new Properties();
properties.putAll(this.env);
return properties;
}
}

View File

@ -156,6 +156,13 @@ public class NacosNamingService implements NamingService {
clientProxy.batchRegisterService(serviceName, groupName, instances);
}
@Override
public void batchDeregisterInstance(String serviceName, String groupName, List<Instance> instances)
throws NacosException {
NamingUtils.batchCheckInstanceIsLegal(instances);
clientProxy.batchDeregisterService(serviceName, groupName, instances);
}
@Override
public void deregisterInstance(String serviceName, String ip, int port) throws NacosException {
deregisterInstance(serviceName, ip, port, Constants.DEFAULT_CLUSTER_NAME);

View File

@ -61,8 +61,11 @@ public class ServiceInfoUpdateService implements Closeable {
private final InstancesChangeNotifier changeNotifier;
private final boolean asyncQuerySubscribeService;
public ServiceInfoUpdateService(Properties properties, ServiceInfoHolder serviceInfoHolder,
NamingClientProxy namingClientProxy, InstancesChangeNotifier changeNotifier) {
this.asyncQuerySubscribeService = isAsyncQueryForSubscribeService(properties);
this.executor = new ScheduledThreadPoolExecutor(initPollingThreadCount(properties),
new NameThreadFactory("com.alibaba.nacos.client.naming.updater"));
this.serviceInfoHolder = serviceInfoHolder;
@ -70,6 +73,13 @@ public class ServiceInfoUpdateService implements Closeable {
this.changeNotifier = changeNotifier;
}
private boolean isAsyncQueryForSubscribeService(Properties properties) {
if (properties == null || !properties.containsKey(PropertyKeyConst.NAMING_ASYNC_QUERY_SUBSCRIBE_SERVICE)) {
return true;
}
return ConvertUtils.toBoolean(properties.getProperty(PropertyKeyConst.NAMING_ASYNC_QUERY_SUBSCRIBE_SERVICE), true);
}
private int initPollingThreadCount(Properties properties) {
if (properties == null) {
return UtilAndComs.DEFAULT_POLLING_THREAD_COUNT;
@ -86,6 +96,9 @@ public class ServiceInfoUpdateService implements Closeable {
* @param clusters clusters
*/
public void scheduleUpdateIfAbsent(String serviceName, String groupName, String clusters) {
if (!asyncQuerySubscribeService) {
return;
}
String serviceKey = ServiceInfo.getKey(NamingUtils.getGroupedName(serviceName, groupName), clusters);
if (futureMap.get(serviceKey) != null) {
return;
@ -193,9 +206,10 @@ public class ServiceInfoUpdateService implements Closeable {
// TODO multiple time can be configured.
delayTime = serviceObj.getCacheMillis() * DEFAULT_UPDATE_CACHE_TIME_MULTIPLE;
resetFailCount();
} catch (NacosException e) {
handleNacosException(e);
} catch (Throwable e) {
incFailCount();
NAMING_LOGGER.warn("[NA] failed to update serviceName: {}", groupedServiceName, e);
handleUnknownException(e);
} finally {
if (!isCancel) {
executor.schedule(this, Math.min(delayTime << failCount, DEFAULT_DELAY * 60),
@ -204,6 +218,20 @@ public class ServiceInfoUpdateService implements Closeable {
}
}
private void handleNacosException(NacosException e) {
incFailCount();
int errorCode = e.getErrCode();
if (NacosException.SERVER_ERROR == errorCode) {
handleUnknownException(e);
}
NAMING_LOGGER.warn("Can't update serviceName: {}, reason: {}", groupedServiceName, e.getErrMsg());
}
private void handleUnknownException(Throwable throwable) {
incFailCount();
NAMING_LOGGER.warn("[NA] failed to update serviceName: {}", groupedServiceName, throwable);
}
private void incFailCount() {
int limit = 6;
if (failCount == limit) {

View File

@ -55,6 +55,17 @@ public interface NamingClientProxy extends Closeable {
*/
void batchRegisterService(String serviceName, String groupName, List<Instance> instances) throws NacosException;
/**
* Batch register instance to service with specified instance properties.
*
* @param serviceName service name
* @param groupName group name
* @param instances deRegister instance
* @throws NacosException nacos exception
* @since 2.2.0
*/
void batchDeregisterService(String serviceName, String groupName, List<Instance> instances) throws NacosException;
/**
* Deregister instance from a service.
*

View File

@ -107,6 +107,17 @@ public class NamingClientProxyDelegate implements NamingClientProxy {
NAMING_LOGGER.info("batchRegisterInstance instances: {} ,serviceName: {} finish.", instances, serviceName);
}
@Override
public void batchDeregisterService(String serviceName, String groupName, List<Instance> instances)
throws NacosException {
NAMING_LOGGER.info("batch DeregisterInstance instances: {} ,serviceName: {} begin.", instances, serviceName);
if (CollectionUtils.isEmpty(instances)) {
NAMING_LOGGER.warn("batch DeregisterInstance instances is Empty:{}", instances);
}
grpcClientProxy.batchDeregisterService(serviceName, groupName, instances);
NAMING_LOGGER.info("batch DeregisterInstance 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

@ -33,6 +33,7 @@ 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;
import com.alibaba.nacos.api.naming.utils.NamingUtils;
import com.alibaba.nacos.api.remote.RemoteConstants;
import com.alibaba.nacos.api.remote.response.Response;
import com.alibaba.nacos.api.remote.response.ResponseCode;
@ -42,6 +43,8 @@ import com.alibaba.nacos.client.naming.cache.ServiceInfoHolder;
import com.alibaba.nacos.client.naming.event.ServerListChangedEvent;
import com.alibaba.nacos.client.naming.remote.AbstractNamingClientProxy;
import com.alibaba.nacos.client.naming.remote.gprc.redo.NamingGrpcRedoService;
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.security.SecurityProxy;
import com.alibaba.nacos.common.notify.Event;
import com.alibaba.nacos.common.notify.NotifyCenter;
@ -49,14 +52,18 @@ import com.alibaba.nacos.common.remote.ConnectionType;
import com.alibaba.nacos.common.remote.client.RpcClient;
import com.alibaba.nacos.common.remote.client.RpcClientFactory;
import com.alibaba.nacos.common.remote.client.ServerListFactory;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.alibaba.nacos.common.utils.JacksonUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.alibaba.nacos.client.utils.LogUtils.NAMING_LOGGER;
@ -124,6 +131,50 @@ public class NamingGrpcClientProxy extends AbstractNamingClientProxy {
doBatchRegisterService(serviceName, groupName, instances);
}
@Override
public void batchDeregisterService(String serviceName, String groupName, List<Instance> instances)
throws NacosException {
List<Instance> retainInstance = getRetainInstance(serviceName, groupName, instances);
batchRegisterService(serviceName, groupName, retainInstance);
}
/**
* Get instance list that need to be deregistered.
* @param serviceName service name
* @param groupName group name
* @param instances instance list
* @return instance list that need to be deregistered.
*/
private List<Instance> getRetainInstance(String serviceName, String groupName, List<Instance> instances) throws NacosException {
if (CollectionUtils.isEmpty(instances)) {
throw new NacosException(NacosException.INVALID_PARAM,
String.format("[Batch deRegistration] need deRegister instance is empty, instances: %s,", instances));
}
String combinedServiceName = NamingUtils.getGroupedName(serviceName, groupName);
InstanceRedoData instanceRedoData = redoService.getRegisteredInstancesBykey(combinedServiceName);
if (!(instanceRedoData instanceof BatchInstanceRedoData)) {
throw new NacosException(NacosException.INVALID_PARAM,
String.format("[Batch deRegistration] batch deRegister is not BatchInstanceRedoData type , instances: %s,", instances));
}
BatchInstanceRedoData batchInstanceRedoData = (BatchInstanceRedoData) instanceRedoData;
List<Instance> allInstance = batchInstanceRedoData.getInstances();
if (CollectionUtils.isEmpty(allInstance)) {
throw new NacosException(NacosException.INVALID_PARAM,
String.format("[Batch deRegistration] not found all registerInstance , serviceName%s , groupName: %s", serviceName, groupName));
}
Map<Instance, Instance> instanceMap = instances
.stream().collect(Collectors.toMap(Function.identity(), Function.identity()));
List<Instance> retainInstances = new ArrayList<>();
for (Instance instance : allInstance) {
if (!instanceMap.containsKey(instance)) {
retainInstances.add(instance);
}
}
return retainInstances;
}
/**
* Execute batch register operation.
*
@ -280,7 +331,7 @@ public class NamingGrpcClientProxy extends AbstractNamingClientProxy {
* @throws NacosException nacos exception
*/
public void doUnsubscribe(String serviceName, String groupName, String clusters) throws NacosException {
SubscribeServiceRequest request = new SubscribeServiceRequest(namespaceId, serviceName, groupName, clusters,
SubscribeServiceRequest request = new SubscribeServiceRequest(namespaceId, groupName, serviceName, clusters,
false);
requestToServer(request, SubscribeServiceResponse.class);
redoService.removeSubscriberForRedo(serviceName, groupName, clusters);

View File

@ -277,6 +277,14 @@ public class NamingGrpcRedoService implements ConnectionEventListener {
return result;
}
/**
* get Cache service.
* @return cache service
*/
public InstanceRedoData getRegisteredInstancesBykey(String combinedServiceName) {
return registeredInstances.get(combinedServiceName);
}
/**
* Shutdown redo service.
*/

View File

@ -172,6 +172,12 @@ public class NamingHttpClientProxy extends AbstractNamingClientProxy {
throw new UnsupportedOperationException("Do not support persistent instances to perform batch registration methods.");
}
@Override
public void batchDeregisterService(String serviceName, String groupName, List<Instance> instances)
throws NacosException {
throw new UnsupportedOperationException("Do not support persistent instances to perform batch de registration methods.");
}
@Override
public void deregisterService(String serviceName, String groupName, Instance instance) throws NacosException {
NAMING_LOGGER

View File

@ -95,21 +95,6 @@ public class InitUtils {
UtilAndComs.nacosUrlBase = UtilAndComs.webContext + "/v1/ns";
UtilAndComs.nacosUrlInstance = UtilAndComs.nacosUrlBase + "/instance";
});
initWebRootContext();
}
/**
* Init web root context.
*/
@Deprecated
public static void initWebRootContext() {
// support the web context with ali-yun if the app deploy by EDAS
final String webContext = System.getProperty(SystemPropertyKeyConst.NAMING_WEB_CONTEXT);
TemplateUtils.stringNotEmptyAndThenExecute(webContext, () -> {
UtilAndComs.webContext = ContextPathUtil.normalizeContextPath(webContext);
UtilAndComs.nacosUrlBase = UtilAndComs.webContext + "/v1/ns";
UtilAndComs.nacosUrlInstance = UtilAndComs.nacosUrlBase + "/instance";
});
}
/**

View File

@ -17,7 +17,6 @@
package com.alibaba.nacos.client.naming.utils;
import com.alibaba.nacos.common.utils.ThreadUtils;
import com.alibaba.nacos.common.utils.VersionUtils;
/**
* Util and constants.
@ -26,10 +25,6 @@ import com.alibaba.nacos.common.utils.VersionUtils;
*/
public class UtilAndComs {
// using com.alibaba.nacos.common.utils.VersionUtils.getFullClientVersion instead.
@Deprecated
public static final String VERSION = VersionUtils.getFullClientVersion();
public static String webContext = "/nacos";
public static String nacosUrlBase = webContext + "/v1/ns";

View File

@ -116,31 +116,4 @@ public class CredentialServiceTest extends TestCase {
Assert.assertEquals(expect, actual);
}
@Test
public void testGetAkAndSk() {
CredentialService credentialService1 = CredentialService.getInstance();
Credentials c = new Credentials();
c.setAccessKey("ak");
c.setSecretKey("sk");
credentialService1.setCredential(c);
Assert.assertEquals("ak", credentialService1.getAccessKey());
Assert.assertEquals("sk", credentialService1.getSecretKey());
}
@Test
public void testSetSecretKey() {
CredentialService credentialService1 = CredentialService.getInstance();
Credentials c = new Credentials();
c.setAccessKey("ak");
c.setSecretKey("sk");
credentialService1.setCredential(c);
credentialService1.setAccessKey("ak1");
credentialService1.setSecretKey("sk1");
Assert.assertEquals("ak1", credentialService1.getAccessKey());
Assert.assertEquals("sk1", credentialService1.getSecretKey());
}
}

View File

@ -21,7 +21,6 @@ import com.alibaba.nacos.api.config.filter.IConfigFilter;
import com.alibaba.nacos.api.config.filter.IConfigFilterChain;
import com.alibaba.nacos.api.config.filter.IConfigRequest;
import com.alibaba.nacos.api.config.filter.IConfigResponse;
import com.alibaba.nacos.api.config.filter.IFilterConfig;
import com.alibaba.nacos.api.exception.NacosException;
import org.junit.Assert;
import org.junit.Test;
@ -43,11 +42,7 @@ public class ConfigFilterChainManagerTest {
this.name = name;
this.order = order;
}
@Override
public void init(IFilterConfig filterConfig) {
}
@Override
public void init(Properties properties) {
}
@ -135,4 +130,4 @@ public class ConfigFilterChainManagerTest {
Assert.assertEquals(2, configContext.getParameter("filterCount"));
}
}
}

View File

@ -20,7 +20,6 @@ import com.alibaba.nacos.api.config.filter.IConfigFilter;
import com.alibaba.nacos.api.config.filter.IConfigFilterChain;
import com.alibaba.nacos.api.config.filter.IConfigRequest;
import com.alibaba.nacos.api.config.filter.IConfigResponse;
import com.alibaba.nacos.api.config.filter.IFilterConfig;
import com.alibaba.nacos.api.exception.NacosException;
import java.util.Properties;
@ -29,11 +28,6 @@ public class DemoFilter1 implements IConfigFilter {
private static final String DEFAULT_NAME = DemoFilter1.class.getName();
@Override
public void init(IFilterConfig filterConfig) {
}
@Override
public void init(Properties properties) {

View File

@ -20,7 +20,6 @@ import com.alibaba.nacos.api.config.filter.IConfigFilter;
import com.alibaba.nacos.api.config.filter.IConfigFilterChain;
import com.alibaba.nacos.api.config.filter.IConfigRequest;
import com.alibaba.nacos.api.config.filter.IConfigResponse;
import com.alibaba.nacos.api.config.filter.IFilterConfig;
import com.alibaba.nacos.api.exception.NacosException;
import java.util.Properties;
@ -29,11 +28,6 @@ public class DemoFilter2 implements IConfigFilter {
private static final String DEFAULT_NAME = DemoFilter2.class.getName();
@Override
public void init(IFilterConfig filterConfig) {
}
@Override
public void init(Properties properties) {

View File

@ -0,0 +1,308 @@
/*
* 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 org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.Properties;
public class NacosClientPropertiesTest {
@BeforeClass
public static void init() {
System.setProperty("nacos.env.first", "jvm");
}
@AfterClass
public static void teardown() {
System.clearProperty("nacos.env.first");
}
@Test
public void testGetProperty() {
NacosClientProperties.PROTOTYPE.setProperty("nacos.home", "/home/nacos");
final String value = NacosClientProperties.PROTOTYPE.getProperty("nacos.home");
Assert.assertEquals("/home/nacos", value);
}
@Test
public void testGetPropertyMultiLayer() {
NacosClientProperties.PROTOTYPE.setProperty("top.layer", "top");
final NacosClientProperties layerAEnv = NacosClientProperties.PROTOTYPE.derive();
layerAEnv.setProperty("a.layer", "a");
final NacosClientProperties layerBEnv = layerAEnv.derive();
layerBEnv.setProperty("b.layer", "b");
final NacosClientProperties layerCEnv = layerBEnv.derive();
layerCEnv.setProperty("c.layer", "c");
String value = layerCEnv.getProperty("c.layer");
Assert.assertEquals("c", value);
value = layerCEnv.getProperty("b.layer");
Assert.assertEquals("b", value);
value = layerCEnv.getProperty("a.layer");
Assert.assertEquals("a", value);
value = layerCEnv.getProperty("top.layer");
Assert.assertEquals("top", value);
}
@Test
public void testGetPropertyDefaultValue() {
final String value = NacosClientProperties.PROTOTYPE.getProperty("nacos.home.default", "/home/default_value");
Assert.assertEquals("/home/default_value", value);
}
@Test
public void testGetBoolean() {
NacosClientProperties.PROTOTYPE.setProperty("use.cluster", "true");
final Boolean value = NacosClientProperties.PROTOTYPE.getBoolean("use.cluster");
Assert.assertTrue(value);
}
@Test
public void testGetBooleanDefaultValue() {
final Boolean value = NacosClientProperties.PROTOTYPE.getBoolean("use.cluster.default", false);
Assert.assertFalse(value);
}
@Test
public void testGetInteger() {
NacosClientProperties.PROTOTYPE.setProperty("max.timeout", "200");
final Integer value = NacosClientProperties.PROTOTYPE.getInteger("max.timeout");
Assert.assertEquals(200, value.intValue());
}
@Test
public void testGetIntegerDefaultValue() {
final Integer value = NacosClientProperties.PROTOTYPE.getInteger("max.timeout.default", 400);
Assert.assertEquals(400, value.intValue());
}
@Test
public void testGetLong() {
NacosClientProperties.PROTOTYPE.setProperty("connection.timeout", "200");
final Long value = NacosClientProperties.PROTOTYPE.getLong("connection.timeout");
Assert.assertEquals(200L, value.longValue());
}
@Test
public void testGetLongDefault() {
final Long value = NacosClientProperties.PROTOTYPE.getLong("connection.timeout.default", 400L);
Assert.assertEquals(400L, value.longValue());
}
@Test
public void testGetPropertyDefaultSetting() {
final String value = NacosClientProperties.PROTOTYPE.getProperty("nacos.home.default.test");
Assert.assertEquals("/home/default_setting", value);
}
@Test
public void setProperty() {
NacosClientProperties.PROTOTYPE.setProperty("nacos.set.property", "true");
final String ret = NacosClientProperties.PROTOTYPE.getProperty("nacos.set.property");
Assert.assertEquals("true", ret);
}
@Test
public void setPropertyWithScope() {
final NacosClientProperties properties = NacosClientProperties.PROTOTYPE.derive();
properties.setProperty("nacos.set.property.scope", "config");
String ret = NacosClientProperties.PROTOTYPE.getProperty("nacos.set.property.scope");
Assert.assertNull(ret);
ret = properties.getProperty("nacos.set.property.scope");
Assert.assertEquals("config", ret);
}
@Test
public void testAddProperties() {
Properties properties = new Properties();
properties.setProperty("nacos.add.properties", "true");
NacosClientProperties.PROTOTYPE.addProperties(properties);
final String ret = NacosClientProperties.PROTOTYPE.getProperty("nacos.add.properties");
Assert.assertEquals("true", ret);
}
@Test
public void testAddPropertiesWithScope() {
Properties properties = new Properties();
properties.setProperty("nacos.add.properties.scope", "config");
final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive();
nacosClientProperties.addProperties(properties);
String ret = NacosClientProperties.PROTOTYPE.getProperty("nacos.add.properties.scope");
Assert.assertNull(ret);
ret = nacosClientProperties.getProperty("nacos.add.properties.scope");
Assert.assertEquals("config", ret);
}
@Test
public void testTestDerive() {
Properties properties = new Properties();
properties.setProperty("nacos.derive.properties.scope", "derive");
final NacosClientProperties nacosClientProperties = NacosClientProperties.PROTOTYPE.derive(properties);
final String value = nacosClientProperties.getProperty("nacos.derive.properties.scope");
Assert.assertEquals("derive", value);
}
@Test
public void testContainsKey() {
NacosClientProperties.PROTOTYPE.setProperty("nacos.contains.key", "true");
boolean ret = NacosClientProperties.PROTOTYPE.containsKey("nacos.contains.key");
Assert.assertTrue(ret);
ret = NacosClientProperties.PROTOTYPE.containsKey("nacos.contains.key.in.sys");
Assert.assertFalse(ret);
}
@Test
public void testContainsKeyMultiLayers() {
NacosClientProperties.PROTOTYPE.setProperty("top.layer", "top");
final NacosClientProperties layerAEnv = NacosClientProperties.PROTOTYPE.derive();
layerAEnv.setProperty("a.layer", "a");
final NacosClientProperties layerBEnv = layerAEnv.derive();
layerBEnv.setProperty("b.layer", "b");
final NacosClientProperties layerCEnv = layerBEnv.derive();
layerCEnv.setProperty("c.layer", "c");
boolean exist = layerCEnv.containsKey("c.layer");
Assert.assertTrue(exist);
exist = layerCEnv.containsKey("b.layer");
Assert.assertTrue(exist);
exist = layerCEnv.containsKey("a.layer");
Assert.assertTrue(exist);
exist = layerCEnv.containsKey("top.layer");
Assert.assertTrue(exist);
}
@Test
public void testContainsKeyWithScope() {
NacosClientProperties.PROTOTYPE.setProperty("nacos.contains.global.scope", "global");
final NacosClientProperties namingProperties = NacosClientProperties.PROTOTYPE.derive();
namingProperties.setProperty("nacos.contains.naming.scope", "naming");
boolean ret = NacosClientProperties.PROTOTYPE.containsKey("nacos.contains.global.scope");
Assert.assertTrue(ret);
ret = NacosClientProperties.PROTOTYPE.containsKey("nacos.contains.naming.scope");
Assert.assertFalse(ret);
ret = namingProperties.containsKey("nacos.contains.naming.scope");
Assert.assertTrue(ret);
ret = namingProperties.containsKey("nacos.contains.global.scope");
Assert.assertTrue(ret);
}
@Test
public void testAsProperties() {
NacosClientProperties.PROTOTYPE.setProperty("nacos.as.properties", "true");
final Properties properties = NacosClientProperties.PROTOTYPE.asProperties();
Assert.assertNotNull(properties);
Assert.assertEquals("true", properties.getProperty("nacos.as.properties"));
}
@Test
public void testAsPropertiesWithScope() {
NacosClientProperties.PROTOTYPE.setProperty("nacos.as.properties.global.scope", "global");
NacosClientProperties.PROTOTYPE.setProperty("nacos.server.addr.scope", "global");
final NacosClientProperties configProperties = NacosClientProperties.PROTOTYPE.derive();
configProperties.setProperty("nacos.server.addr.scope", "config");
final Properties properties = configProperties.asProperties();
Assert.assertNotNull(properties);
String ret = properties.getProperty("nacos.as.properties.global.scope");
Assert.assertEquals("global", ret);
ret = properties.getProperty("nacos.server.addr.scope");
Assert.assertEquals("config", ret);
}
@Test
public void testGetPropertyWithScope() {
NacosClientProperties.PROTOTYPE.setProperty("nacos.global.scope", "global");
final NacosClientProperties configProperties = NacosClientProperties.PROTOTYPE.derive();
configProperties.setProperty("nacos.config.scope", "config");
final NacosClientProperties namingProperties = NacosClientProperties.PROTOTYPE.derive();
namingProperties.setProperty("nacos.naming.scope", "naming");
String ret = NacosClientProperties.PROTOTYPE.getProperty("nacos.global.scope");
Assert.assertEquals("global", ret);
ret = NacosClientProperties.PROTOTYPE.getProperty("nacos.config.scope");
Assert.assertNull(ret);
ret = NacosClientProperties.PROTOTYPE.getProperty("nacos.naming.scope");
Assert.assertNull(ret);
ret = configProperties.getProperty("nacos.config.scope");
Assert.assertEquals("config", ret);
ret = configProperties.getProperty("nacos.global.scope");
Assert.assertEquals("global", ret);
ret = configProperties.getProperty("nacos.naming.scope");
Assert.assertNull(ret);
ret = namingProperties.getProperty("nacos.naming.scope");
Assert.assertEquals("naming", ret);
ret = namingProperties.getProperty("nacos.global.scope");
Assert.assertEquals("global", ret);
ret = namingProperties.getProperty("nacos.config.scope");
Assert.assertNull(ret);
}
}

View File

@ -1,50 +0,0 @@
/*
* 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 org.junit.Assert;
import org.junit.Test;
import java.lang.reflect.Proxy;
import java.util.Properties;
public class NacosEnvironmentFactoryTest {
@Test(expected = IllegalStateException.class)
public void testCreateEnvironment() {
final NacosEnvironment environment = NacosEnvironmentFactory.createEnvironment();
Assert.assertNotNull(environment);
Assert.assertTrue(Proxy.isProxyClass(environment.getClass()));
environment.getProperty("test.exception");
}
@Test
public void testNacosEnvInit() {
final NacosEnvironment environment = NacosEnvironmentFactory.createEnvironment();
final NacosEnvironmentFactory.NacosEnvironmentDelegate invocationHandler =
(NacosEnvironmentFactory.NacosEnvironmentDelegate) Proxy.getInvocationHandler(
environment);
Properties properties = new Properties();
properties.setProperty("init.nacos", "true");
invocationHandler.init(properties);
final String property = environment.getProperty("init.nacos");
Assert.assertEquals("true", property);
}
}

View File

@ -1,174 +0,0 @@
/*
* 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 org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Properties;
public class NacosEnvsTest {
static MockedStatic<NacosEnvironmentFactory> mockedStatic;
@BeforeClass
public static void before() {
mockedStatic = Mockito.mockStatic(NacosEnvironmentFactory.class);
mockedStatic.when(NacosEnvironmentFactory::createEnvironment).thenReturn(createProxy());
}
@AfterClass
public static void teardown() {
if (mockedStatic != null) {
mockedStatic.close();
}
}
private static NacosEnvironment createProxy() {
return (NacosEnvironment) Proxy.newProxyInstance(NacosEnvironmentFactory.class.getClassLoader(),
new Class[] {NacosEnvironment.class}, new NacosEnvironmentFactory.NacosEnvironmentDelegate() {
volatile NacosEnvironment environment;
@Override
public void init(Properties properties) {
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 NEnvs#init method then try it again.");
}
return method.invoke(environment, args);
}
});
}
@Test
public void testGetProperty() {
final Properties properties = new Properties();
properties.setProperty("nacos.home", "/home/nacos");
NacosEnvs.init(properties);
final String value = NacosEnvs.getProperty("nacos.home");
Assert.assertEquals("/home/nacos", value);
}
@Test
public void testGetPropertyDefaultValue() {
final Properties properties = new Properties();
NacosEnvs.init(properties);
final String value = NacosEnvs.getProperty("nacos.home", "/home/default_value");
Assert.assertEquals("/home/default_value", value);
}
@Test
public void testGetBoolean() {
final Properties properties = new Properties();
properties.setProperty("use.cluster", "true");
NacosEnvs.init(properties);
final Boolean value = NacosEnvs.getBoolean("use.cluster");
Assert.assertTrue(value);
}
@Test
public void testGetBooleanDefaultValue() {
final Properties properties = new Properties();
NacosEnvs.init(properties);
final Boolean value = NacosEnvs.getBoolean("use.cluster", false);
Assert.assertFalse(value);
}
@Test
public void testGetInteger() {
final Properties properties = new Properties();
properties.setProperty("max.timeout", "200");
NacosEnvs.init(properties);
final Integer value = NacosEnvs.getInteger("max.timeout");
Assert.assertEquals(200, value.intValue());
}
@Test
public void testGetIntegerDefaultValue() {
final Properties properties = new Properties();
NacosEnvs.init(properties);
final Integer value = NacosEnvs.getInteger("max.timeout", 400);
Assert.assertEquals(400, value.intValue());
}
@Test
public void testGetLong() {
final Properties properties = new Properties();
properties.setProperty("connection.timeout", "200");
NacosEnvs.init(properties);
final Long value = NacosEnvs.getLong("connection.timeout");
Assert.assertEquals(200L, value.longValue());
}
@Test
public void testGetLongDefault() {
final Properties properties = new Properties();
NacosEnvs.init(properties);
final Long value = NacosEnvs.getLong("connection.timeout", 400L);
Assert.assertEquals(400L, value.longValue());
}
@Test
public void testGetPropertyJvmFirst() {
System.setProperty("nacos.envs.search", "jvm");
System.setProperty("nacos.home", "/home/jvm_first");
Properties properties = new Properties();
properties.setProperty("nacos.home", "/home/properties_first");
NacosEnvs.init(properties);
final String value = NacosEnvs.getProperty("nacos.home");
Assert.assertEquals("/home/jvm_first", value);
System.clearProperty("nacos.envs.search");
System.clearProperty("nacos.home");
}
@Test
public void testGetPropertyDefaultSetting() {
Properties properties = new Properties();
NacosEnvs.init(properties);
final String value = NacosEnvs.getProperty("nacos.home.default.test");
Assert.assertEquals("/home/default_setting", value);
}
}

View File

@ -116,6 +116,27 @@ public class NacosNamingServiceTest {
instances -> CollectionUtils.isEqualCollection(instanceList, instances)));
}
@Test
public void testBatchDeRegisterInstance() throws NacosException {
Instance instance = new Instance();
String serviceName = "service1";
String ip = "1.1.1.1";
int port = 10000;
instance.setServiceName(serviceName);
instance.setEphemeral(true);
instance.setPort(port);
instance.setIp(ip);
List<Instance> instanceList = new ArrayList<>();
instanceList.add(instance);
//when
try {
client.batchDeregisterInstance(serviceName, Constants.DEFAULT_GROUP, instanceList);
} catch (Exception e) {
Assert.assertTrue(e instanceof NacosException);
Assert.assertTrue(e.getMessage().contains("not found"));
}
}
@Test
public void testRegisterInstance2() throws NacosException {
//given

View File

@ -109,6 +109,12 @@ public class AbstractNamingClientProxyTest {
}
@Override
public void batchDeregisterService(String serviceName, String groupName, List<Instance> instances)
throws NacosException {
}
@Override
public void deregisterService(String serviceName, String groupName, Instance instance) throws NacosException {

View File

@ -48,6 +48,7 @@ import com.alibaba.nacos.common.notify.NotifyCenter;
import com.alibaba.nacos.common.remote.ConnectionType;
import com.alibaba.nacos.common.remote.client.Connection;
import com.alibaba.nacos.common.remote.client.RpcClient;
import com.alibaba.nacos.common.remote.client.RpcClientConfig;
import com.alibaba.nacos.common.remote.client.ServerListFactory;
import org.junit.Assert;
import org.junit.Before;
@ -62,8 +63,10 @@ import org.mockito.junit.MockitoJUnitRunner;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@ -77,7 +80,7 @@ import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class NamingGrpcClientProxyTest {
@Rule
public ExpectedException expectedException = ExpectedException.none();
@ -165,7 +168,7 @@ public class NamingGrpcClientProxyTest {
public void testRegisterServiceThrowsException() throws NacosException {
expectedException.expect(NacosException.class);
expectedException.expectMessage("Request nacos server failed: ");
when(this.rpcClient.request(Mockito.any())).thenReturn(null);
try {
@ -284,8 +287,11 @@ public class NamingGrpcClientProxyTest {
verify(this.rpcClient, times(1)).request(argThat(request -> {
if (request instanceof SubscribeServiceRequest) {
SubscribeServiceRequest request1 = (SubscribeServiceRequest) request;
// not subscribe
return !request1.isSubscribe();
// verify request fields
return !request1.isSubscribe() && SERVICE_NAME.equals(request1.getServiceName()) && GROUP_NAME.equals(
request1.getGroupName()) && CLUSTERS.equals(request1.getClusters()) && NAMESPACE_ID.equals(
request1.getNamespace());
}
return false;
}));
@ -320,7 +326,42 @@ public class NamingGrpcClientProxyTest {
@Test
public void testServerListChanged() throws Exception {
RpcClient rpc = new RpcClient("testServerListHasChanged", factory) {
RpcClient rpc = new RpcClient(new RpcClientConfig() {
@Override
public String name() {
return "testServerListHasChanged";
}
@Override
public int retryTimes() {
return 3;
}
@Override
public long timeOutMills() {
return 3000L;
}
@Override
public long connectionKeepAlive() {
return 5000L;
}
@Override
public int healthCheckRetryTimes() {
return 1;
}
@Override
public long healthCheckTimeOut() {
return 3000L;
}
@Override
public Map<String, String> labels() {
return new HashMap<>();
}
}, factory) {
@Override
public ConnectionType getConnectionType() {
return ConnectionType.GRPC;

View File

@ -34,5 +34,7 @@ public interface HttpHeaderConsts {
String CONNECTION = "Requester";
String REQUEST_ID = "RequestId";
String REQUEST_MODULE = "Request-Module";
String APP_FILED = "app";
String CLIENT_IP = "clientIp";
}

View File

@ -27,11 +27,11 @@ import java.util.concurrent.atomic.AtomicLong;
*/
@SuppressWarnings({"PMD.AbstractClassShouldStartWithAbstractNamingRule"})
public abstract class Event implements Serializable {
private static final long serialVersionUID = -3731383194964997493L;
private static final AtomicLong SEQUENCE = new AtomicLong(0);
private final long sequence = SEQUENCE.getAndIncrement();
/**
@ -51,5 +51,15 @@ public abstract class Event implements Serializable {
public String scope() {
return null;
}
/**
* Whether is plugin event. If so, the event can be dropped when no publish and subscriber without any hint. Default
* false
*
* @return {@code true} if is plugin event, otherwise {@code false}
*/
public boolean isPluginEvent() {
return false;
}
}

View File

@ -301,6 +301,9 @@ public class NotifyCenter {
if (publisher != null) {
return publisher.publish(event);
}
if (event.isPluginEvent()) {
return true;
}
LOGGER.warn("There are no [{}] publishers for this event, please register", topic);
return false;
}

View File

@ -30,9 +30,9 @@ import java.util.List;
public abstract class SmartSubscriber extends Subscriber {
/**
* Returns which event type are smartsubscriber interested in.
* Returns which event type are smart subscriber interested in.
*
* @return The interestd event types.
* @return The interested event types.
*/
public abstract List<Class<? extends Event>> subscribeTypes();

View File

@ -69,6 +69,6 @@ public abstract class Subscriber<T extends Event> {
* @return Whether the event's scope matches current subscriber
*/
public boolean scopeMatches(T event) {
return event.scope() == null;
return true;
}
}

View File

@ -33,6 +33,7 @@ import com.alibaba.nacos.common.lifecycle.Closeable;
import com.alibaba.nacos.common.remote.ConnectionType;
import com.alibaba.nacos.common.remote.PayloadRegistry;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.alibaba.nacos.common.utils.InternetAddressUtil;
import com.alibaba.nacos.common.utils.LoggerUtils;
import com.alibaba.nacos.common.utils.NumberUtils;
import com.alibaba.nacos.common.utils.StringUtils;
@ -40,7 +41,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
@ -79,23 +80,10 @@ public abstract class RpcClient implements Closeable {
protected volatile Connection currentConnection;
protected Map<String, String> labels = new HashMap<>();
private String name;
private String tenant;
private static final int RETRY_TIMES = 3;
private static final long DEFAULT_TIMEOUT_MILLS = 3000L;
protected ClientAbilities clientAbilities;
/**
* default keep alive time 5s.
*/
private long keepAliveTime = 5000L;
private long lastActiveTimeStamp = System.currentTimeMillis();
/**
@ -110,28 +98,34 @@ public abstract class RpcClient implements Closeable {
private static final Pattern EXCLUDE_PROTOCOL_PATTERN = Pattern.compile("(?<=\\w{1,5}://)(.*)");
protected RpcClientConfig rpcClientConfig;
static {
PayloadRegistry.init();
}
public RpcClient(String name) {
this(name, null);
public RpcClient(RpcClientConfig rpcClientConfig) {
this(rpcClientConfig, null);
}
public RpcClient(ServerListFactory serverListFactory) {
this(null, serverListFactory);
public RpcClient(RpcClientConfig rpcClientConfig, ServerListFactory serverListFactory) {
this.rpcClientConfig = rpcClientConfig;
this.serverListFactory = serverListFactory;
init();
}
public RpcClient(String name, ServerListFactory serverListFactory) {
this.name = name;
if (serverListFactory != null) {
this.serverListFactory = serverListFactory;
protected void init() {
if (this.serverListFactory != null) {
rpcClientStatus.compareAndSet(RpcClientStatus.WAIT_INIT, RpcClientStatus.INITIALIZED);
LoggerUtils.printIfInfoEnabled(LOGGER, "RpcClient init in constructor, ServerListFactory = {}",
serverListFactory.getClass().getName());
}
}
public Map<String, String> labels() {
return Collections.unmodifiableMap(rpcClientConfig.labels());
}
/**
* init client abilities.
*
@ -154,35 +148,11 @@ public abstract class RpcClient implements Closeable {
this.serverListFactory = serverListFactory;
rpcClientStatus.compareAndSet(RpcClientStatus.WAIT_INIT, RpcClientStatus.INITIALIZED);
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] RpcClient init, ServerListFactory = {}", name,
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] RpcClient init, ServerListFactory = {}", rpcClientConfig.name(),
serverListFactory.getClass().getName());
return this;
}
/**
* init labels.
*
* @param labels labels
*/
public RpcClient labels(Map<String, String> labels) {
this.labels.putAll(labels);
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] RpcClient init label, labels = {}", name, this.labels);
return this;
}
/**
* init keepalive time.
*
* @param keepAliveTime keepAliveTime
* @param timeUnit timeUnit
*/
public RpcClient keepAlive(long keepAliveTime, TimeUnit timeUnit) {
this.keepAliveTime = keepAliveTime * timeUnit.toMillis(keepAliveTime);
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] RpcClient init keepalive time, keepAliveTimeMillis = {}", name,
keepAliveTime);
return this;
}
/**
* Notify when client disconnected.
*/
@ -190,13 +160,13 @@ public abstract class RpcClient implements Closeable {
if (connectionEventListeners.isEmpty()) {
return;
}
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Notify disconnected event to listeners", name);
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Notify disconnected event to listeners", rpcClientConfig.name());
for (ConnectionEventListener connectionEventListener : connectionEventListeners) {
try {
connectionEventListener.onDisConnect();
} catch (Throwable throwable) {
LoggerUtils.printIfErrorEnabled(LOGGER, "[{}] Notify disconnect listener error, listener = {}", name,
connectionEventListener.getClass().getName());
LoggerUtils.printIfErrorEnabled(LOGGER, "[{}] Notify disconnect listener error, listener = {}",
rpcClientConfig.name(), connectionEventListener.getClass().getName());
}
}
}
@ -208,13 +178,13 @@ public abstract class RpcClient implements Closeable {
if (connectionEventListeners.isEmpty()) {
return;
}
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Notify connected event to listeners.", name);
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Notify connected event to listeners.", rpcClientConfig.name());
for (ConnectionEventListener connectionEventListener : connectionEventListeners) {
try {
connectionEventListener.onConnected();
} catch (Throwable throwable) {
LoggerUtils.printIfErrorEnabled(LOGGER, "[{}] Notify connect listener error, listener = {}", name,
connectionEventListener.getClass().getName());
LoggerUtils.printIfErrorEnabled(LOGGER, "[{}] Notify connect listener error, listener = {}",
rpcClientConfig.name(), connectionEventListener.getClass().getName());
}
}
}
@ -310,18 +280,18 @@ public abstract class RpcClient implements Closeable {
break;
}
ReconnectContext reconnectContext = reconnectionSignal
.poll(keepAliveTime, TimeUnit.MILLISECONDS);
.poll(rpcClientConfig.connectionKeepAlive(), TimeUnit.MILLISECONDS);
if (reconnectContext == null) {
// check alive time.
if (System.currentTimeMillis() - lastActiveTimeStamp >= keepAliveTime) {
if (System.currentTimeMillis() - lastActiveTimeStamp >= rpcClientConfig.connectionKeepAlive()) {
boolean isHealthy = healthCheck();
if (!isHealthy) {
if (currentConnection == null) {
continue;
}
LoggerUtils.printIfInfoEnabled(LOGGER,
"[{}] Server healthy check fail, currentConnection = {}", name,
currentConnection.getConnectionId());
"[{}] Server healthy check fail, currentConnection = {}",
rpcClientConfig.name(), currentConnection.getConnectionId());
RpcClientStatus rpcClientStatus = RpcClient.this.rpcClientStatus.get();
if (RpcClientStatus.SHUTDOWN.equals(rpcClientStatus)) {
@ -359,8 +329,8 @@ public abstract class RpcClient implements Closeable {
}
if (!serverExist) {
LoggerUtils.printIfInfoEnabled(LOGGER,
"[{}] Recommend server is not in server list, ignore recommend server {}", name,
reconnectContext.serverInfo.getAddress());
"[{}] Recommend server is not in server list, ignore recommend server {}",
rpcClientConfig.name(), reconnectContext.serverInfo.getAddress());
reconnectContext.serverInfo = null;
@ -373,31 +343,33 @@ public abstract class RpcClient implements Closeable {
}
});
// connect to server, try to connect to server sync RETRY_TIMES times, async starting if failed.
// connect to server, try to connect to server sync retryTimes times, async starting if failed.
Connection connectToServer = null;
rpcClientStatus.set(RpcClientStatus.STARTING);
int startUpRetryTimes = RETRY_TIMES;
int startUpRetryTimes = rpcClientConfig.retryTimes();
while (startUpRetryTimes > 0 && connectToServer == null) {
try {
startUpRetryTimes--;
ServerInfo serverInfo = nextRpcServer();
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Try to connect to server on start up, server: {}", name,
serverInfo);
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Try to connect to server on start up, server: {}",
rpcClientConfig.name(), serverInfo);
connectToServer = connectToServer(serverInfo);
} catch (Throwable e) {
LoggerUtils.printIfWarnEnabled(LOGGER,
"[{}] Fail to connect to server on start up, error message = {}, start up retry times left: {}",
name, e.getMessage(), startUpRetryTimes, e);
rpcClientConfig.name(), e.getMessage(), startUpRetryTimes, e);
}
}
if (connectToServer != null) {
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Success to connect to server [{}] on start up, connectionId = {}",
name, connectToServer.serverInfo.getAddress(), connectToServer.getConnectionId());
LoggerUtils
.printIfInfoEnabled(LOGGER, "[{}] Success to connect to server [{}] on start up, connectionId = {}",
rpcClientConfig.name(), connectToServer.serverInfo.getAddress(),
connectToServer.getConnectionId());
this.currentConnection = connectToServer;
rpcClientStatus.set(RpcClientStatus.RUNNING);
eventLinkedBlockingQueue.offer(new ConnectionEvent(ConnectionEvent.CONNECTED));
@ -440,7 +412,7 @@ public abstract class RpcClient implements Closeable {
}
}
} catch (Exception e) {
LoggerUtils.printIfErrorEnabled(LOGGER, "[{}] Switch server error, {}", name, e);
LoggerUtils.printIfErrorEnabled(LOGGER, "[{}] Switch server error, {}", rpcClientConfig.name(), e);
}
return new ConnectResetResponse();
}
@ -464,12 +436,17 @@ public abstract class RpcClient implements Closeable {
if (this.currentConnection == null) {
return false;
}
try {
Response response = this.currentConnection.request(healthCheckRequest, 3000L);
// not only check server is ok, also check connection is register.
return response != null && response.isSuccess();
} catch (NacosException e) {
// ignore
int reTryTimes = rpcClientConfig.healthCheckRetryTimes();
while (reTryTimes >= 0) {
reTryTimes--;
try {
Response response = this.currentConnection
.request(healthCheckRequest, rpcClientConfig.healthCheckTimeOut());
// not only check server is ok, also check connection is register.
return response != null && response.isSuccess();
} catch (NacosException e) {
// ignore
}
}
return false;
}
@ -495,14 +472,14 @@ public abstract class RpcClient implements Closeable {
AtomicReference<ServerInfo> recommendServer = new AtomicReference<>(recommendServerInfo);
if (onRequestFail && healthCheck()) {
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Server check success, currentServer is {} ", name,
currentConnection.serverInfo.getAddress());
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Server check success, currentServer is {} ",
rpcClientConfig.name(), currentConnection.serverInfo.getAddress());
rpcClientStatus.set(RpcClientStatus.RUNNING);
return;
}
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Try to reconnect to a new server, server is {}", name,
recommendServerInfo == null ? " not appointed, will choose a random server."
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Try to reconnect to a new server, server is {}",
rpcClientConfig.name(), recommendServerInfo == null ? " not appointed, will choose a random server."
: (recommendServerInfo.getAddress() + ", will try it once."));
// loop until start client success.
@ -520,13 +497,16 @@ public abstract class RpcClient implements Closeable {
// 2.create a new channel to new server
Connection connectionNew = connectToServer(serverInfo);
if (connectionNew != null) {
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Success to connect a server [{}], connectionId = {}",
name, serverInfo.getAddress(), connectionNew.getConnectionId());
LoggerUtils
.printIfInfoEnabled(LOGGER, "[{}] Success to connect a server [{}], connectionId = {}",
rpcClientConfig.name(), serverInfo.getAddress(),
connectionNew.getConnectionId());
// successfully create a new connect.
if (currentConnection != null) {
LoggerUtils.printIfInfoEnabled(LOGGER,
"[{}] Abandon prev connection, server is {}, connectionId is {}", name,
currentConnection.serverInfo.getAddress(), currentConnection.getConnectionId());
"[{}] Abandon prev connection, server is {}, connectionId is {}",
rpcClientConfig.name(), currentConnection.serverInfo.getAddress(),
currentConnection.getConnectionId());
// set current connection to enable connection event.
currentConnection.setAbandon(true);
closeConnection(currentConnection);
@ -558,8 +538,9 @@ public abstract class RpcClient implements Closeable {
if (reConnectTimes > 0
&& reConnectTimes % RpcClient.this.serverListFactory.getServerList().size() == 0) {
LoggerUtils.printIfInfoEnabled(LOGGER,
"[{}] Fail to connect server, after trying {} times, last try server is {}, error = {}", name,
reConnectTimes, serverInfo, lastException == null ? "unknown" : lastException);
"[{}] Fail to connect server, after trying {} times, last try server is {}, error = {}",
rpcClientConfig.name(), reConnectTimes, serverInfo,
lastException == null ? "unknown" : lastException);
if (Integer.MAX_VALUE == retryTurns) {
retryTurns = 50;
} else {
@ -583,11 +564,14 @@ public abstract class RpcClient implements Closeable {
}
if (isShutdown()) {
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Client is shutdown, stop reconnect to server", name);
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Client is shutdown, stop reconnect to server",
rpcClientConfig.name());
}
} catch (Exception e) {
LoggerUtils.printIfWarnEnabled(LOGGER, "[{}] Fail to reconnect to server, error is {}", name, e);
LoggerUtils
.printIfWarnEnabled(LOGGER, "[{}] Fail to reconnect to server, error is {}", rpcClientConfig.name(),
e);
}
}
@ -632,7 +616,7 @@ public abstract class RpcClient implements Closeable {
* @return response from server.
*/
public Response request(Request request) throws NacosException {
return request(request, DEFAULT_TIMEOUT_MILLS);
return request(request, rpcClientConfig.timeOutMills());
}
/**
@ -646,7 +630,7 @@ public abstract class RpcClient implements Closeable {
Response response;
Exception exceptionThrow = null;
long start = System.currentTimeMillis();
while (retryTimes < RETRY_TIMES && System.currentTimeMillis() < timeoutMills + start) {
while (retryTimes < rpcClientConfig.retryTimes() && System.currentTimeMillis() < timeoutMills + start) {
boolean waitReconnect = false;
try {
if (this.currentConnection == null || !isRunning()) {
@ -687,8 +671,9 @@ public abstract class RpcClient implements Closeable {
}
}
LoggerUtils.printIfErrorEnabled(LOGGER, "Send request fail, request = {}, retryTimes = {}, errorMessage = {}",
request, retryTimes, e.getMessage());
LoggerUtils.printIfErrorEnabled(LOGGER,
"Send request fail, request = {}, retryTimes = {}, errorMessage = {}", request, retryTimes,
e.getMessage());
exceptionThrow = e;
@ -719,7 +704,8 @@ public abstract class RpcClient implements Closeable {
Exception exceptionToThrow = null;
long start = System.currentTimeMillis();
while (retryTimes < RETRY_TIMES && System.currentTimeMillis() < start + callback.getTimeout()) {
while (retryTimes < rpcClientConfig.retryTimes() && System.currentTimeMillis() < start + callback
.getTimeout()) {
boolean waitReconnect = false;
try {
if (this.currentConnection == null || !isRunning()) {
@ -737,9 +723,9 @@ public abstract class RpcClient implements Closeable {
// Do nothing.
}
}
LoggerUtils
.printIfErrorEnabled(LOGGER, "[{}] Send request fail, request = {}, retryTimes = {}, errorMessage = {}",
name, request, retryTimes, e.getMessage());
LoggerUtils.printIfErrorEnabled(LOGGER,
"[{}] Send request fail, request = {}, retryTimes = {}, errorMessage = {}",
rpcClientConfig.name(), request, retryTimes, e.getMessage());
exceptionToThrow = e;
}
@ -768,7 +754,8 @@ public abstract class RpcClient implements Closeable {
int retryTimes = 0;
long start = System.currentTimeMillis();
Exception exceptionToThrow = null;
while (retryTimes < RETRY_TIMES && System.currentTimeMillis() < start + DEFAULT_TIMEOUT_MILLS) {
while (retryTimes < rpcClientConfig.retryTimes() && System.currentTimeMillis() < start + rpcClientConfig
.timeOutMills()) {
boolean waitReconnect = false;
try {
if (this.currentConnection == null || !isRunning()) {
@ -785,9 +772,9 @@ public abstract class RpcClient implements Closeable {
// Do nothing.
}
}
LoggerUtils
.printIfErrorEnabled(LOGGER, "[{}] Send request fail, request = {}, retryTimes = {}, errorMessage = {}",
name, request, retryTimes, e.getMessage());
LoggerUtils.printIfErrorEnabled(LOGGER,
"[{}] Send request fail, request = {}, retryTimes = {}, errorMessage = {}",
rpcClientConfig.name(), request, retryTimes, e.getMessage());
exceptionToThrow = e;
}
@ -824,21 +811,21 @@ public abstract class RpcClient implements Closeable {
*/
protected Response handleServerRequest(final Request request) {
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Receive server push request, request = {}, requestId = {}", name,
request.getClass().getSimpleName(), request.getRequestId());
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Receive server push request, request = {}, requestId = {}",
rpcClientConfig.name(), request.getClass().getSimpleName(), request.getRequestId());
lastActiveTimeStamp = System.currentTimeMillis();
for (ServerRequestHandler serverRequestHandler : serverRequestHandlers) {
try {
Response response = serverRequestHandler.requestReply(request);
if (response != null) {
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Ack server push request, request = {}, requestId = {}", name,
request.getClass().getSimpleName(), request.getRequestId());
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Ack server push request, request = {}, requestId = {}",
rpcClientConfig.name(), request.getClass().getSimpleName(), request.getRequestId());
return response;
}
} catch (Exception e) {
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] HandleServerRequest:{}, errorMessage = {}", name,
serverRequestHandler.getClass().getName(), e.getMessage());
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] HandleServerRequest:{}, errorMessage = {}",
rpcClientConfig.name(), serverRequestHandler.getClass().getName(), e.getMessage());
}
}
@ -852,8 +839,8 @@ public abstract class RpcClient implements Closeable {
*/
public synchronized void registerConnectionListener(ConnectionEventListener connectionEventListener) {
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Registry connection listener to current client:{}", name,
connectionEventListener.getClass().getName());
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Registry connection listener to current client:{}",
rpcClientConfig.name(), connectionEventListener.getClass().getName());
this.connectionEventListeners.add(connectionEventListener);
}
@ -863,7 +850,7 @@ public abstract class RpcClient implements Closeable {
* @param serverRequestHandler serverRequestHandler
*/
public synchronized void registerServerRequestHandler(ServerRequestHandler serverRequestHandler) {
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Register server push request handler:{}", name,
LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Register server push request handler:{}", rpcClientConfig.name(),
serverRequestHandler.getClass().getName());
this.serverRequestHandlers.add(serverRequestHandler);
@ -875,16 +862,7 @@ public abstract class RpcClient implements Closeable {
* @return property value of name
*/
public String getName() {
return name;
}
/**
* Setter method for property <tt>name</tt>.
*
* @param name value to be assigned to property name
*/
public void setName(String name) {
this.name = name;
return rpcClientConfig.name();
}
/**
@ -918,8 +896,7 @@ public abstract class RpcClient implements Closeable {
if (matcher.find()) {
serverAddress = matcher.group(1);
}
String[] ipPortTuple = serverAddress.split(Constants.COLON, 2);
String[] ipPortTuple = InternetAddressUtil.splitIPPortStr(serverAddress);
int defaultPort = Integer.parseInt(System.getProperty("nacos.server.port", "8848"));
String serverPort = CollectionUtils.getOrDefault(ipPortTuple, 1, Integer.toString(defaultPort));
@ -1019,7 +996,7 @@ public abstract class RpcClient implements Closeable {
* @return property value of labels
*/
public Map<String, String> getLabels() {
return labels;
return rpcClientConfig.labels();
}
class ReconnectContext {

View File

@ -0,0 +1,77 @@
/*
* 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.common.remote.client;
import java.util.Map;
/**
* RpcClientConfig.
*
* @author karsonto
*/
public interface RpcClientConfig {
/**
* get name.
*
* @return name.
*/
String name();
/**
* get request retry times.
*
* @return retryTimes.
*/
int retryTimes();
/**
* get time out mills.
*
* @return timeOutMills.
*/
long timeOutMills();
/**
* get connection keep alive time.
*
* @return connectionKeepAlive.
*/
long connectionKeepAlive();
/**
* get health check retry times.
*
* @return healthCheckRetryTimes.
*/
int healthCheckRetryTimes();
/**
* get health check time out.
*
* @return healthCheckTimeOut.
*/
long healthCheckTimeOut();
/**
* get map of labels.
*
* @return labels.
*/
Map<String, String> labels();
}

View File

@ -18,7 +18,6 @@ package com.alibaba.nacos.common.remote.client;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.common.remote.ConnectionType;
import com.alibaba.nacos.common.remote.client.grpc.GrpcClient;
import com.alibaba.nacos.common.remote.client.grpc.GrpcClusterClient;
import com.alibaba.nacos.common.remote.client.grpc.GrpcSdkClient;
import org.slf4j.Logger;
@ -94,11 +93,7 @@ public class RpcClientFactory {
return CLIENT_MAP.computeIfAbsent(clientName, clientNameInner -> {
LOGGER.info("[RpcClientFactory] create a new rpc client of " + clientName);
try {
GrpcClient client = new GrpcSdkClient(clientNameInner);
client.setThreadPoolCoreSize(threadPoolCoreSize);
client.setThreadPoolMaxSize(threadPoolMaxSize);
client.labels(labels);
return client;
return new GrpcSdkClient(clientNameInner, threadPoolCoreSize, threadPoolMaxSize, labels);
} catch (Throwable throwable) {
LOGGER.error("Error to init GrpcSdkClient for client name :" + clientName, throwable);
throw throwable;
@ -134,13 +129,9 @@ public class RpcClientFactory {
throw new UnsupportedOperationException("unsupported connection type :" + connectionType.getType());
}
return CLIENT_MAP.computeIfAbsent(clientName, clientNameInner -> {
GrpcClient client = new GrpcClusterClient(clientNameInner);
client.setThreadPoolCoreSize(threadPoolCoreSize);
client.setThreadPoolMaxSize(threadPoolMaxSize);
client.labels(labels);
return client;
});
return CLIENT_MAP.computeIfAbsent(clientName,
clientNameInner -> new GrpcClusterClient(clientNameInner, threadPoolCoreSize, threadPoolMaxSize,
labels));
}
}

View File

@ -0,0 +1,385 @@
/*
* 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.common.remote.client.grpc;
import com.alibaba.nacos.common.utils.ThreadUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
/**
* Default grpc client config.
*
* @author karsonto
*/
public class DefaultGrpcClientConfig implements GrpcClientConfig {
private String name;
private int retryTimes;
private long timeOutMills;
private long connectionKeepAlive;
private long threadPoolKeepAlive;
private int threadPoolCoreSize;
private int threadPoolMaxSize;
private long serverCheckTimeOut;
private int threadPoolQueueSize;
private int maxInboundMessageSize;
private int channelKeepAlive;
private int healthCheckRetryTimes;
private long healthCheckTimeOut;
private Map<String, String> labels;
/**
* constructor.
*
* @param builder builder of DefaultGrpcClientConfig builder.
*/
private DefaultGrpcClientConfig(Builder builder) {
this.name = builder.name;
this.retryTimes = loadIntegerConfig(GrpcConstants.GRPC_RETRY_TIMES, builder.retryTimes);
this.timeOutMills = loadLongConfig(GrpcConstants.GRPC_TIMEOUT_MILLS, builder.timeOutMills);
this.connectionKeepAlive = loadLongConfig(GrpcConstants.GRPC_CONNECT_KEEP_ALIVE_TIME,
builder.connectionKeepAlive);
this.threadPoolKeepAlive = loadLongConfig(GrpcConstants.GRPC_THREADPOOL_KEEPALIVETIME,
builder.threadPoolKeepAlive);
this.threadPoolCoreSize = loadIntegerConfig(GrpcConstants.GRPC_THREADPOOL_CORE_SIZE,
builder.threadPoolCoreSize);
this.threadPoolMaxSize = loadIntegerConfig(GrpcConstants.GRPC_THREADPOOL_MAX_SIZE, builder.threadPoolMaxSize);
this.serverCheckTimeOut = loadLongConfig(GrpcConstants.GRPC_SERVER_CHECK_TIMEOUT, builder.serverCheckTimeOut);
this.threadPoolQueueSize = loadIntegerConfig(GrpcConstants.GRPC_QUEUESIZE, builder.threadPoolQueueSize);
this.maxInboundMessageSize = loadIntegerConfig(GrpcConstants.GRPC_MAX_INBOUND_MESSAGE_SIZE,
builder.maxInboundMessageSize);
this.channelKeepAlive = loadIntegerConfig(GrpcConstants.GRPC_CHANNEL_KEEP_ALIVE_TIME, builder.channelKeepAlive);
this.healthCheckRetryTimes = loadIntegerConfig(GrpcConstants.GRPC_HEALTHCHECK_RETRY_TIMES,
builder.healthCheckRetryTimes);
this.healthCheckTimeOut = loadLongConfig(GrpcConstants.GRPC_HEALTHCHECK_TIMEOUT, builder.healthCheckTimeOut);
this.labels = builder.labels;
}
private int loadIntegerConfig(String key, int builderValue) {
return Integer.getInteger(key, builderValue);
}
private long loadLongConfig(String key, long builderValue) {
return Long.getLong(key, builderValue);
}
@Override
public String name() {
return this.name;
}
@Override
public int retryTimes() {
return retryTimes;
}
@Override
public long timeOutMills() {
return timeOutMills;
}
@Override
public long connectionKeepAlive() {
return connectionKeepAlive;
}
@Override
public int threadPoolCoreSize() {
return threadPoolCoreSize;
}
@Override
public int threadPoolMaxSize() {
return threadPoolMaxSize;
}
@Override
public long threadPoolKeepAlive() {
return threadPoolKeepAlive;
}
@Override
public long serverCheckTimeOut() {
return serverCheckTimeOut;
}
@Override
public int threadPoolQueueSize() {
return threadPoolQueueSize;
}
@Override
public int maxInboundMessageSize() {
return maxInboundMessageSize;
}
@Override
public int channelKeepAlive() {
return channelKeepAlive;
}
@Override
public int healthCheckRetryTimes() {
return healthCheckRetryTimes;
}
@Override
public long healthCheckTimeOut() {
return healthCheckTimeOut;
}
@Override
public Map<String, String> labels() {
return this.labels;
}
public static Builder newBuilder() {
return new Builder();
}
public static class Builder {
private String name;
private int retryTimes = 3;
private long timeOutMills = 3000L;
private long connectionKeepAlive = 5000L;
private long threadPoolKeepAlive = 10000L;
private int threadPoolCoreSize = ThreadUtils.getSuitableThreadCount(2);
private int threadPoolMaxSize = ThreadUtils.getSuitableThreadCount(8);
private long serverCheckTimeOut = 3000L;
private int threadPoolQueueSize = 10000;
private int maxInboundMessageSize = 10 * 1024 * 1024;
private int channelKeepAlive = 6 * 60 * 1000;
private int healthCheckRetryTimes = 3;
private long healthCheckTimeOut = 3000L;
private Map<String, String> labels = new HashMap<>();
private Builder() {
}
/**
* Set config from properties.
*
* @param properties properties
* @return Builder
*/
public Builder fromProperties(Properties properties) {
if (properties.contains(GrpcConstants.GRPC_NAME)) {
this.name = properties.getProperty(GrpcConstants.GRPC_NAME);
}
if (properties.contains(GrpcConstants.GRPC_RETRY_TIMES)) {
this.retryTimes = Integer.parseInt(properties.getProperty(GrpcConstants.GRPC_RETRY_TIMES));
}
if (properties.contains(GrpcConstants.GRPC_TIMEOUT_MILLS)) {
this.timeOutMills = Long.parseLong(properties.getProperty(GrpcConstants.GRPC_TIMEOUT_MILLS));
}
if (properties.contains(GrpcConstants.GRPC_CONNECT_KEEP_ALIVE_TIME)) {
this.connectionKeepAlive = Long
.parseLong(properties.getProperty(GrpcConstants.GRPC_CONNECT_KEEP_ALIVE_TIME));
}
if (properties.contains(GrpcConstants.GRPC_THREADPOOL_KEEPALIVETIME)) {
this.threadPoolKeepAlive = Long
.parseLong(properties.getProperty(GrpcConstants.GRPC_THREADPOOL_KEEPALIVETIME));
}
if (properties.contains(GrpcConstants.GRPC_THREADPOOL_CORE_SIZE)) {
this.threadPoolCoreSize = Integer
.parseInt(properties.getProperty(GrpcConstants.GRPC_THREADPOOL_CORE_SIZE));
}
if (properties.contains(GrpcConstants.GRPC_THREADPOOL_MAX_SIZE)) {
this.threadPoolMaxSize = Integer
.parseInt(properties.getProperty(GrpcConstants.GRPC_THREADPOOL_MAX_SIZE));
}
if (properties.contains(GrpcConstants.GRPC_SERVER_CHECK_TIMEOUT)) {
this.serverCheckTimeOut = Long
.parseLong(properties.getProperty(GrpcConstants.GRPC_SERVER_CHECK_TIMEOUT));
}
if (properties.contains(GrpcConstants.GRPC_QUEUESIZE)) {
this.threadPoolQueueSize = Integer.parseInt(properties.getProperty(GrpcConstants.GRPC_QUEUESIZE));
}
if (properties.contains(GrpcConstants.GRPC_MAX_INBOUND_MESSAGE_SIZE)) {
this.maxInboundMessageSize = Integer
.parseInt(properties.getProperty(GrpcConstants.GRPC_MAX_INBOUND_MESSAGE_SIZE));
}
if (properties.contains(GrpcConstants.GRPC_CHANNEL_KEEP_ALIVE_TIME)) {
this.channelKeepAlive = Integer
.parseInt(properties.getProperty(GrpcConstants.GRPC_CHANNEL_KEEP_ALIVE_TIME));
}
if (properties.contains(GrpcConstants.GRPC_HEALTHCHECK_RETRY_TIMES)) {
this.healthCheckRetryTimes = Integer
.parseInt(properties.getProperty(GrpcConstants.GRPC_HEALTHCHECK_RETRY_TIMES));
}
if (properties.contains(GrpcConstants.GRPC_HEALTHCHECK_TIMEOUT)) {
this.healthCheckTimeOut = Long
.parseLong(properties.getProperty(GrpcConstants.GRPC_HEALTHCHECK_TIMEOUT));
}
return this;
}
/**
* set client name.
*/
public Builder setName(String name) {
this.name = name;
return this;
}
/**
* set retryTimes.
*/
public Builder setRetryTimes(int retryTimes) {
this.retryTimes = retryTimes;
return this;
}
/**
* set timeOutMills.
*/
public Builder setTimeOutMills(long timeOutMills) {
this.timeOutMills = timeOutMills;
return this;
}
/**
* set connectionKeepAlive.
*/
public Builder setConnectionKeepAlive(long connectionKeepAlive) {
this.connectionKeepAlive = connectionKeepAlive;
return this;
}
/**
* set threadPoolKeepAlive.
*/
public Builder setThreadPoolKeepAlive(Long threadPoolKeepAlive) {
this.threadPoolKeepAlive = threadPoolKeepAlive;
return this;
}
/**
* set threadPoolCoreSize.
*/
public Builder setThreadPoolCoreSize(Integer threadPoolCoreSize) {
if (!Objects.isNull(threadPoolCoreSize)) {
this.threadPoolCoreSize = threadPoolCoreSize;
}
return this;
}
/**
* set threadPoolMaxSize.
*/
public Builder setThreadPoolMaxSize(Integer threadPoolMaxSize) {
if (!Objects.isNull(threadPoolMaxSize)) {
this.threadPoolMaxSize = threadPoolMaxSize;
}
return this;
}
/**
* set serverCheckTimeOut.
*/
public Builder setServerCheckTimeOut(Long serverCheckTimeOut) {
this.serverCheckTimeOut = serverCheckTimeOut;
return this;
}
/**
* set threadPoolQueueSize.
*/
public Builder setThreadPoolQueueSize(int threadPoolQueueSize) {
this.threadPoolQueueSize = threadPoolQueueSize;
return this;
}
/**
* set maxInboundMessageSize.
*/
public Builder setMaxInboundMessageSize(int maxInboundMessageSize) {
this.maxInboundMessageSize = maxInboundMessageSize;
return this;
}
/**
* set channelKeepAlive.
*/
public Builder setChannelKeepAlive(int channelKeepAlive) {
this.channelKeepAlive = channelKeepAlive;
return this;
}
/**
* set healthCheckRetryTimes.
*/
public Builder setHealthCheckRetryTimes(int healthCheckRetryTimes) {
this.healthCheckRetryTimes = healthCheckRetryTimes;
return this;
}
/**
* set healthCheckTimeOut.
*/
public Builder setHealthCheckTimeOut(long healthCheckTimeOut) {
this.healthCheckTimeOut = healthCheckTimeOut;
return this;
}
/**
* set labels.
*/
public Builder setLabels(Map<String, String> labels) {
this.labels.putAll(labels);
return this;
}
/**
* build GrpcClientConfig.
*/
public GrpcClientConfig build() {
return new DefaultGrpcClientConfig(this);
}
}
}

View File

@ -30,9 +30,9 @@ import com.alibaba.nacos.common.remote.ConnectionType;
import com.alibaba.nacos.common.remote.client.Connection;
import com.alibaba.nacos.common.remote.client.RpcClient;
import com.alibaba.nacos.common.remote.client.RpcClientStatus;
import com.alibaba.nacos.common.remote.client.ServerListFactory;
import com.alibaba.nacos.common.utils.LoggerUtils;
import com.alibaba.nacos.common.utils.ThreadFactoryBuilder;
import com.alibaba.nacos.common.utils.ThreadUtils;
import com.alibaba.nacos.common.utils.VersionUtils;
import com.google.common.util.concurrent.ListenableFuture;
import io.grpc.CompressorRegistry;
@ -43,6 +43,8 @@ import io.grpc.stub.StreamObserver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@ -56,19 +58,11 @@ import java.util.concurrent.TimeUnit;
@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule")
public abstract class GrpcClient extends RpcClient {
static final Logger LOGGER = LoggerFactory.getLogger(GrpcClient.class);
private static final Logger LOGGER = LoggerFactory.getLogger(GrpcClient.class);
protected static final String NACOS_SERVER_GRPC_PORT_OFFSET_KEY = "nacos.server.grpc.port.offset";
private final GrpcClientConfig clientConfig;
private ThreadPoolExecutor grpcExecutor = null;
private Integer threadPoolCoreSize;
private Integer threadPoolMaxSize;
private static final long DEFAULT_MAX_INBOUND_MESSAGE_SIZE = 10 * 1024 * 1024L;
private static final long DEFAULT_KEEP_ALIVE_TIME = 6 * 60 * 1000;
private ThreadPoolExecutor grpcExecutor;
@Override
public ConnectionType getConnectionType() {
@ -76,47 +70,64 @@ public abstract class GrpcClient extends RpcClient {
}
/**
* Empty constructor.
* constructor.
*
* @param name .
*/
public GrpcClient(String name) {
super(name);
this(DefaultGrpcClientConfig.newBuilder().setName(name).build());
}
/**
* Set core size of thread pool.
* constructor.
*
* @param threadPoolCoreSize core size of thread pool for grpc.
* @param properties .
*/
public void setThreadPoolCoreSize(Integer threadPoolCoreSize) {
this.threadPoolCoreSize = threadPoolCoreSize;
public GrpcClient(Properties properties) {
this(DefaultGrpcClientConfig.newBuilder().fromProperties(properties).build());
}
/**
* Set max size of thread pool.
* constructor.
*
* @param threadPoolMaxSize max size of thread pool for grpc.
* @param clientConfig .
*/
public void setThreadPoolMaxSize(Integer threadPoolMaxSize) {
this.threadPoolMaxSize = threadPoolMaxSize;
public GrpcClient(GrpcClientConfig clientConfig) {
super(clientConfig);
this.clientConfig = clientConfig;
}
protected Integer getThreadPoolCoreSize() {
return threadPoolCoreSize != null ? threadPoolCoreSize : ThreadUtils.getSuitableThreadCount(2);
/**
* constructor.
*
* @param clientConfig .
* @param serverListFactory .
*/
public GrpcClient(GrpcClientConfig clientConfig, ServerListFactory serverListFactory) {
super(clientConfig, serverListFactory);
this.clientConfig = clientConfig;
}
protected Integer getThreadPoolMaxSize() {
return threadPoolMaxSize != null ? threadPoolMaxSize : ThreadUtils.getSuitableThreadCount(8);
/**
* constructor.
*
* @param name .
* @param threadPoolCoreSize .
* @param threadPoolMaxSize .
* @param labels .
*/
public GrpcClient(String name, Integer threadPoolCoreSize, Integer threadPoolMaxSize, Map<String, String> labels) {
this(DefaultGrpcClientConfig.newBuilder().setName(name).setThreadPoolCoreSize(threadPoolCoreSize)
.setThreadPoolMaxSize(threadPoolMaxSize).setLabels(labels).build());
}
protected ThreadPoolExecutor createGrpcExecutor(String serverIp) {
ThreadPoolExecutor grpcExecutor = new ThreadPoolExecutor(
getThreadPoolCoreSize(),
getThreadPoolMaxSize(),
10L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(10000),
new ThreadFactoryBuilder()
.daemon(true)
.nameFormat("nacos-grpc-client-executor-" + serverIp + "-%d")
// Thread name will use String.format, ipv6 maybe contain special word %, so handle it first.
serverIp = serverIp.replaceAll("%", "-");
ThreadPoolExecutor grpcExecutor = new ThreadPoolExecutor(clientConfig.threadPoolCoreSize(),
clientConfig.threadPoolMaxSize(), clientConfig.threadPoolKeepAlive(), TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(clientConfig.threadPoolQueueSize()),
new ThreadFactoryBuilder().daemon(true).nameFormat("nacos-grpc-client-executor-" + serverIp + "-%d")
.build());
grpcExecutor.allowCoreThreadTimeOut(true);
return grpcExecutor;
@ -130,7 +141,7 @@ public abstract class GrpcClient extends RpcClient {
grpcExecutor.shutdown();
}
}
/**
* Create a stub using a channel.
*
@ -140,7 +151,7 @@ public abstract class GrpcClient extends RpcClient {
private RequestGrpc.RequestFutureStub createNewChannelStub(ManagedChannel managedChannelTemp) {
return RequestGrpc.newFutureStub(managedChannelTemp);
}
/**
* create a new channel with specific server address.
*
@ -149,24 +160,14 @@ public abstract class GrpcClient extends RpcClient {
* @return if server check success,return a non-null channel.
*/
private ManagedChannel createNewManagedChannel(String serverIp, int serverPort) {
ManagedChannelBuilder<?> managedChannelBuilder = ManagedChannelBuilder.forAddress(serverIp, serverPort).executor(grpcExecutor)
.compressorRegistry(CompressorRegistry.getDefaultInstance()).decompressorRegistry(DecompressorRegistry.getDefaultInstance())
.maxInboundMessageSize(getInboundMessageSize()).keepAliveTime(keepAliveTimeMillis(), TimeUnit.MILLISECONDS).usePlaintext();
ManagedChannelBuilder<?> managedChannelBuilder = ManagedChannelBuilder.forAddress(serverIp, serverPort)
.executor(grpcExecutor).compressorRegistry(CompressorRegistry.getDefaultInstance())
.decompressorRegistry(DecompressorRegistry.getDefaultInstance())
.maxInboundMessageSize(clientConfig.maxInboundMessageSize())
.keepAliveTime(clientConfig.channelKeepAlive(), TimeUnit.MILLISECONDS).usePlaintext();
return managedChannelBuilder.build();
}
private int getInboundMessageSize() {
String messageSize = System.getProperty("nacos.remote.client.grpc.maxinbound.message.size",
String.valueOf(DEFAULT_MAX_INBOUND_MESSAGE_SIZE));
return Integer.parseInt(messageSize);
}
private int keepAliveTimeMillis() {
String keepAliveTimeMillis = System
.getProperty("nacos.remote.grpc.keep.alive.millis", String.valueOf(DEFAULT_KEEP_ALIVE_TIME));
return Integer.parseInt(keepAliveTimeMillis);
}
/**
* shutdown a channel.
*
@ -192,7 +193,7 @@ public abstract class GrpcClient extends RpcClient {
ServerCheckRequest serverCheckRequest = new ServerCheckRequest();
Payload grpcRequest = GrpcUtils.convert(serverCheckRequest);
ListenableFuture<Payload> responseFuture = requestBlockingStub.request(grpcRequest);
Payload response = responseFuture.get(3000L, TimeUnit.MILLISECONDS);
Payload response = responseFuture.get(clientConfig.serverCheckTimeOut(), TimeUnit.MILLISECONDS);
//receive connection unregister response here,not check response is success.
return (Response) GrpcUtils.parse(response);
} catch (Exception e) {

View File

@ -0,0 +1,77 @@
/*
* 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.common.remote.client.grpc;
import com.alibaba.nacos.common.remote.client.RpcClientConfig;
/**
* GrpcCleint config. Use to collect and init Grpc client configuration.
*
* @author karsonto
*/
public interface GrpcClientConfig extends RpcClientConfig {
/**
* get threadPoolCoreSize.
*
* @return threadPoolCoreSize.
*/
int threadPoolCoreSize();
/**
* get threadPoolMaxSize.
*
* @return threadPoolMaxSize.
*/
int threadPoolMaxSize();
/**
* get thread pool keep alive time.
*
* @return threadPoolKeepAlive.
*/
long threadPoolKeepAlive();
/**
* get server check time out.
*
* @return serverCheckTimeOut.
*/
long serverCheckTimeOut();
/**
* get thread pool queue size.
*
* @return threadPoolQueueSize.
*/
int threadPoolQueueSize();
/**
* get maxInboundMessage size.
*
* @return maxInboundMessageSize.
*/
int maxInboundMessageSize();
/**
* get channelKeepAlive time.
*
* @return channelKeepAlive.
*/
int channelKeepAlive();
}

View File

@ -18,6 +18,9 @@ package com.alibaba.nacos.common.remote.client.grpc;
import com.alibaba.nacos.api.common.Constants;
import java.util.Map;
import java.util.Properties;
/**
* gRPC client for cluster.
*
@ -35,9 +38,40 @@ public class GrpcClusterClient extends GrpcClient {
super(name);
}
/**
* Empty constructor.
*
* @param config of GrpcClientConfig.
*/
public GrpcClusterClient(GrpcClientConfig config) {
super(config);
}
/**
* Constructor.
*
* @param properties .
*/
public GrpcClusterClient(Properties properties) {
super(properties);
}
/**
* Constructor.
*
* @param name name of client.
* @param threadPoolCoreSize .
* @param threadPoolMaxSize .
* @param labels .
*/
public GrpcClusterClient(String name, Integer threadPoolCoreSize, Integer threadPoolMaxSize,
Map<String, String> labels) {
super(name, threadPoolCoreSize, threadPoolMaxSize, labels);
}
@Override
public int rpcPortOffset() {
return Integer.parseInt(System.getProperty(NACOS_SERVER_GRPC_PORT_OFFSET_KEY,
return Integer.parseInt(System.getProperty(GrpcConstants.NACOS_SERVER_GRPC_PORT_OFFSET_KEY,
String.valueOf(Constants.CLUSTER_GRPC_PORT_DEFAULT_OFFSET)));
}

View File

@ -0,0 +1,107 @@
/*
* 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.common.remote.client.grpc;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
* GrpcConsts.
*
* @author karsonto
*/
public class GrpcConstants {
public static final String NACOS_SERVER_GRPC_PORT_OFFSET_KEY = "nacos.server.grpc.port.offset";
public static final String NACOS_CLIENT_GRPC = "nacos.remote.client.grpc";
@GRpcConfigLabel
public static final String GRPC_NAME = NACOS_CLIENT_GRPC + ".name";
@GRpcConfigLabel
public static final String GRPC_THREADPOOL_KEEPALIVETIME = NACOS_CLIENT_GRPC + ".pool.alive";
@GRpcConfigLabel
public static final String GRPC_THREADPOOL_CORE_SIZE = NACOS_CLIENT_GRPC + ".pool.core.size";
@GRpcConfigLabel
public static final String GRPC_RETRY_TIMES = NACOS_CLIENT_GRPC + ".retry.times";
@GRpcConfigLabel
public static final String GRPC_TIMEOUT_MILLS = NACOS_CLIENT_GRPC + ".timeout";
@GRpcConfigLabel
public static final String GRPC_CONNECT_KEEP_ALIVE_TIME = NACOS_CLIENT_GRPC + ".connect.keep.alive";
@GRpcConfigLabel
public static final String GRPC_THREADPOOL_MAX_SIZE = NACOS_CLIENT_GRPC + ".pool.max.size";
@GRpcConfigLabel
public static final String GRPC_SERVER_CHECK_TIMEOUT = NACOS_CLIENT_GRPC + ".server.check.timeout";
@GRpcConfigLabel
public static final String GRPC_QUEUESIZE = NACOS_CLIENT_GRPC + ".queue.size";
@GRpcConfigLabel
public static final String GRPC_HEALTHCHECK_RETRY_TIMES = NACOS_CLIENT_GRPC + ".health.retry";
@GRpcConfigLabel
public static final String GRPC_HEALTHCHECK_TIMEOUT = NACOS_CLIENT_GRPC + ".health.timeout";
@GRpcConfigLabel
public static final String GRPC_MAX_INBOUND_MESSAGE_SIZE = NACOS_CLIENT_GRPC + ".maxinbound.message.size";
@GRpcConfigLabel
public static final String GRPC_CHANNEL_KEEP_ALIVE_TIME = NACOS_CLIENT_GRPC + ".channel.keep.alive";
private static final Set<String> CONFIG_NAMES = new HashSet<>();
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
protected @interface GRpcConfigLabel {
}
static {
Class clazz = GrpcConstants.class;
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
declaredField.setAccessible(true);
if (declaredField.getType().equals(String.class) && null != declaredField.getAnnotation(
GRpcConfigLabel.class)) {
try {
CONFIG_NAMES.add((String) declaredField.get(null));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
public static Set<String> getRpcParams() {
return Collections.unmodifiableSet(CONFIG_NAMES);
}
}

View File

@ -18,6 +18,9 @@ package com.alibaba.nacos.common.remote.client.grpc;
import com.alibaba.nacos.api.common.Constants;
import java.util.Map;
import java.util.Properties;
/**
* gRPC client for sdk.
*
@ -27,7 +30,7 @@ import com.alibaba.nacos.api.common.Constants;
public class GrpcSdkClient extends GrpcClient {
/**
* Empty constructor.
* Constructor.
*
* @param name name of client.
*/
@ -35,9 +38,40 @@ public class GrpcSdkClient extends GrpcClient {
super(name);
}
/**
* Constructor.
*
* @param properties .
*/
public GrpcSdkClient(Properties properties) {
super(properties);
}
/**
* Constructor.
*
* @param name name of client.
* @param threadPoolCoreSize .
* @param threadPoolMaxSize .
* @param labels .
*/
public GrpcSdkClient(String name, Integer threadPoolCoreSize, Integer threadPoolMaxSize,
Map<String, String> labels) {
super(name, threadPoolCoreSize, threadPoolMaxSize, labels);
}
/**
* constructor.
*
* @param config of GrpcClientConfig.
*/
public GrpcSdkClient(GrpcClientConfig config) {
super(config);
}
@Override
public int rpcPortOffset() {
return Integer.parseInt(System.getProperty(NACOS_SERVER_GRPC_PORT_OFFSET_KEY,
return Integer.parseInt(System.getProperty(GrpcConstants.NACOS_SERVER_GRPC_PORT_OFFSET_KEY,
String.valueOf(Constants.SDK_GRPC_PORT_DEFAULT_OFFSET)));
}

View File

@ -32,6 +32,8 @@ import com.google.protobuf.ByteString;
import com.google.protobuf.UnsafeByteOperations;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
/**
* gRPC utils, use to parse request and response.
@ -59,8 +61,7 @@ public class GrpcUtils {
payloadBuilder.setMetadata(metaBuilder.build());
// request body .
request.clearHeaders();
byte[] jsonBytes = JacksonUtils.toJsonBytes(request);
byte[] jsonBytes = convertRequestToByte(request);
return payloadBuilder
.setBody(Any.newBuilder().setValue(UnsafeByteOperations.unsafeWrap(jsonBytes)))
.build();
@ -77,11 +78,11 @@ public class GrpcUtils {
Metadata newMeta = Metadata.newBuilder().setType(request.getClass().getSimpleName())
.setClientIp(NetUtils.localIP()).putAllHeaders(request.getHeaders()).build();
request.clearHeaders();
byte[] jsonBytes = JacksonUtils.toJsonBytes(request);
byte[] jsonBytes = convertRequestToByte(request);
Payload.Builder builder = Payload.newBuilder();
return builder
.setBody(Any.newBuilder().setValue(UnsafeByteOperations.unsafeWrap(jsonBytes)))
.setMetadata(newMeta).build();
@ -103,6 +104,14 @@ public class GrpcUtils {
.setMetadata(metaBuilder.build()).build();
}
private static byte[] convertRequestToByte(Request request) {
Map<String, String> requestHeaders = new HashMap<>(request.getHeaders());
request.clearHeaders();
byte[] jsonBytes = JacksonUtils.toJsonBytes(request);
request.putAllHeader(requestHeaders);
return jsonBytes;
}
/**
* parse payload to request/response model.
*

View File

@ -31,4 +31,9 @@ public class NamingTraceEvent extends TraceEvent {
String serviceNamespace, String serviceGroup, String name) {
super(eventType, eventTime, serviceNamespace, serviceGroup, name);
}
@Override
public boolean isPluginEvent() {
return true;
}
}

View File

@ -103,7 +103,6 @@ public class TraceEventPublisher extends Thread implements ShardedEventPublisher
boolean success = this.queue.offer(event);
if (!success) {
LOGGER.warn("Trace Event Publish failed, event : {}, publish queue size : {}", event, currentEventSize());
return true;
}
return true;
}

View File

@ -50,7 +50,6 @@ public class TraceEventPublisherFactory implements EventPublisherFactory {
@Override
public EventPublisher apply(final Class<? extends Event> eventType, final Integer maxQueueSize) {
// Like ClientEvent$ClientChangeEvent cache by ClientEvent
Class<? extends Event> cachedEventType = TraceEvent.class;
for (Class<? extends Event> publisherEvent : publisherEvents) {

View File

@ -104,7 +104,7 @@ public class RpcClientFactoryTest {
RpcClient client = RpcClientFactory
.createClient("testClient", ConnectionType.GRPC, Collections.singletonMap("labelKey", "labelValue"));
Assert.assertEquals(Collections.singletonMap("labelKey", "labelValue"), client.labels);
Assert.assertEquals(Collections.singletonMap("labelKey", "labelValue"), client.rpcClientConfig.labels());
Assert.assertEquals(ConnectionType.GRPC, client.getConnectionType());
Assert.assertEquals("testClient", CollectionUtils.getOnlyElement(RpcClientFactory.getAllClientEntries()).getKey());
}
@ -134,7 +134,7 @@ public class RpcClientFactoryTest {
Collections.singletonMap("labelKey", "labelValue")
);
Assert.assertEquals(Collections.singletonMap("labelKey", "labelValue"), client.labels);
Assert.assertEquals(Collections.singletonMap("labelKey", "labelValue"), client.rpcClientConfig.labels());
Assert.assertEquals(ConnectionType.GRPC, client.getConnectionType());
Assert.assertEquals("testClient", CollectionUtils.getOnlyElement(RpcClientFactory.getAllClientEntries()).getKey());
}

View File

@ -21,6 +21,7 @@ import com.alibaba.nacos.api.remote.RequestCallBack;
import com.alibaba.nacos.api.remote.request.Request;
import com.alibaba.nacos.api.remote.response.ErrorResponse;
import com.alibaba.nacos.common.remote.ConnectionType;
import com.alibaba.nacos.common.remote.client.grpc.DefaultGrpcClientConfig;
import com.alibaba.nacos.common.remote.client.grpc.GrpcConnection;
import org.junit.After;
import org.junit.Assert;
@ -36,10 +37,12 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
import java.util.Random;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.atLeastOnce;
@ -49,24 +52,21 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class RpcClientTest {
RpcClient rpcClient;
Field keepAliveTimeField;
Field serverListFactoryField;
Field reconnectionSignalField;
Field retryTimesField;
Field timeoutMillsField;
Method resolveServerInfoMethod;
Method healthCheck;
Answer<?> runAsSync;
Answer<?> notInvoke;
@ -77,9 +77,47 @@ public class RpcClientTest {
@Mock
Connection connection;
RpcClientConfig rpcClientConfig;
@Before
public void setUp() throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException {
rpcClient = spy(new RpcClient("testClient") {
rpcClientConfig = spy(new RpcClientConfig() {
@Override
public String name() {
return "test";
}
@Override
public int retryTimes() {
return 1;
}
@Override
public long timeOutMills() {
return 3000L;
}
@Override
public long connectionKeepAlive() {
return 5000L;
}
@Override
public int healthCheckRetryTimes() {
return 1;
}
@Override
public long healthCheckTimeOut() {
return 3000L;
}
@Override
public Map<String, String> labels() {
return new HashMap<>();
}
});
rpcClient = spy(new RpcClient(rpcClientConfig) {
@Override
public ConnectionType getConnectionType() {
return null;
@ -96,9 +134,6 @@ public class RpcClientTest {
}
});
keepAliveTimeField = RpcClient.class.getDeclaredField("keepAliveTime");
keepAliveTimeField.setAccessible(true);
serverListFactoryField = RpcClient.class.getDeclaredField("serverListFactory");
serverListFactoryField.setAccessible(true);
@ -108,21 +143,12 @@ public class RpcClientTest {
modifiersField1.setAccessible(true);
modifiersField1.setInt(reconnectionSignalField, reconnectionSignalField.getModifiers() & ~Modifier.FINAL);
retryTimesField = RpcClient.class.getDeclaredField("RETRY_TIMES");
retryTimesField.setAccessible(true);
Field modifiersField3 = Field.class.getDeclaredField("modifiers");
modifiersField3.setAccessible(true);
modifiersField3.setInt(retryTimesField, retryTimesField.getModifiers() & ~Modifier.FINAL);
timeoutMillsField = RpcClient.class.getDeclaredField("DEFAULT_TIMEOUT_MILLS");
timeoutMillsField.setAccessible(true);
Field modifiersField4 = Field.class.getDeclaredField("modifiers");
modifiersField4.setAccessible(true);
modifiersField4.setInt(timeoutMillsField, timeoutMillsField.getModifiers() & ~Modifier.FINAL);
resolveServerInfoMethod = RpcClient.class.getDeclaredMethod("resolveServerInfo", String.class);
resolveServerInfoMethod.setAccessible(true);
healthCheck = RpcClient.class.getDeclaredMethod("healthCheck");
healthCheck.setAccessible(true);
runAsSync = invocationOnMock -> {
Runnable runnable = (Runnable) invocationOnMock.getArguments()[0];
runnable.run();
@ -134,7 +160,7 @@ public class RpcClientTest {
@After
public void tearDown() throws IllegalAccessException {
rpcClient.labels.clear();
rpcClientConfig.labels().clear();
rpcClient.rpcClientStatus.set(RpcClientStatus.WAIT_INIT);
serverListFactoryField.set(rpcClient, null);
((Queue<?>) reconnectionSignalField.get(rpcClient)).clear();
@ -147,13 +173,48 @@ public class RpcClientTest {
public void testInitServerListFactory() {
rpcClient.rpcClientStatus.set(RpcClientStatus.WAIT_INIT);
rpcClient.serverListFactory(serverListFactory);
Assert.assertEquals(RpcClientStatus.INITIALIZED, rpcClient.rpcClientStatus.get());
assertEquals(RpcClientStatus.INITIALIZED, rpcClient.rpcClientStatus.get());
rpcClient.rpcClientStatus.set(RpcClientStatus.INITIALIZED);
rpcClient.serverListFactory(serverListFactory);
Assert.assertEquals(RpcClientStatus.INITIALIZED, rpcClient.rpcClientStatus.get());
assertEquals(RpcClientStatus.INITIALIZED, rpcClient.rpcClientStatus.get());
RpcClient client1 = new RpcClient("test", serverListFactory) {
RpcClient client1 = new RpcClient(new RpcClientConfig() {
@Override
public String name() {
return "test";
}
@Override
public int retryTimes() {
return 3;
}
@Override
public long timeOutMills() {
return 3000L;
}
@Override
public long connectionKeepAlive() {
return 5000L;
}
@Override
public int healthCheckRetryTimes() {
return 1;
}
@Override
public long healthCheckTimeOut() {
return 3000L;
}
@Override
public Map<String, String> labels() {
return new HashMap<>();
}
}, serverListFactory) {
@Override
public ConnectionType getConnectionType() {
return null;
@ -169,9 +230,9 @@ public class RpcClientTest {
return null;
}
};
Assert.assertEquals(RpcClientStatus.INITIALIZED, client1.rpcClientStatus.get());
assertEquals(RpcClientStatus.INITIALIZED, client1.rpcClientStatus.get());
RpcClient client2 = new RpcClient(serverListFactory) {
RpcClient client2 = new RpcClient(rpcClientConfig, serverListFactory) {
@Override
public ConnectionType getConnectionType() {
return null;
@ -187,30 +248,21 @@ public class RpcClientTest {
return null;
}
};
Assert.assertEquals(RpcClientStatus.INITIALIZED, client2.rpcClientStatus.get());
assertEquals(RpcClientStatus.INITIALIZED, client2.rpcClientStatus.get());
}
@Test
public void testLabels() {
rpcClient.labels(Collections.singletonMap("labelKey1", "labelValue1"));
when(rpcClientConfig.labels()).thenReturn(Collections.singletonMap("labelKey1", "labelValue1"));
Map.Entry<String, String> element = rpcClient.getLabels().entrySet().iterator().next();
Assert.assertEquals("labelKey1", element.getKey());
Assert.assertEquals("labelValue1", element.getValue());
assertEquals("labelKey1", element.getKey());
assertEquals("labelValue1", element.getValue());
// accumulate labels
rpcClient.labels(Collections.singletonMap("labelKey2", "labelValue2"));
Assert.assertEquals(2, rpcClient.getLabels().size());
}
@Test
public void testKeepAlive() throws IllegalAccessException {
rpcClient.keepAlive(1, TimeUnit.SECONDS);
long keepAliveTime = (long) keepAliveTimeField.get(rpcClient);
Assert.assertEquals(1000L, keepAliveTime);
rpcClient.keepAlive(1, TimeUnit.MINUTES);
keepAliveTime = (long) keepAliveTimeField.get(rpcClient);
Assert.assertEquals(60000L, keepAliveTime);
Map<String, String> map = new HashMap<>();
map.put("labelKey2", "labelValue2");
when(rpcClientConfig.labels()).thenReturn(map);
assertEquals(1, rpcClient.getLabels().size());
}
@Test
@ -221,7 +273,7 @@ public class RpcClientTest {
rpcClient.onServerListChange();
int afterSize = ((Queue<?>) reconnectionSignalField.get(rpcClient)).size();
Assert.assertEquals(beforeSize, afterSize);
assertEquals(beforeSize, afterSize);
}
@Test
@ -232,7 +284,7 @@ public class RpcClientTest {
rpcClient.onServerListChange();
int afterSize = ((Queue<?>) reconnectionSignalField.get(rpcClient)).size();
Assert.assertEquals(beforeSize, afterSize);
assertEquals(beforeSize, afterSize);
}
@Test
@ -242,11 +294,11 @@ public class RpcClientTest {
rpcClient.serverListFactory(serverListFactory);
rpcClient.currentConnection = new GrpcConnection(new RpcClient.ServerInfo("10.10.10.10", 8848), null);
doReturn(Collections.singletonList("")).when(serverListFactory).getServerList();
when(serverListFactory.getServerList()).thenReturn(Collections.singletonList("127.0.0.1"));
rpcClient.onServerListChange();
int afterSize = ((Queue<?>) reconnectionSignalField.get(rpcClient)).size();
Assert.assertEquals(beforeSize + 1, afterSize);
assertEquals(beforeSize + 1, afterSize);
}
@Test
@ -255,35 +307,35 @@ public class RpcClientTest {
rpcClient.serverListFactory(serverListFactory);
rpcClient.currentConnection = new GrpcConnection(new RpcClient.ServerInfo("10.10.10.10", 8848), null);
doReturn(Collections.singletonList("http://10.10.10.10:8848")).when(serverListFactory).getServerList();
rpcClient.onServerListChange();
int afterSize = ((Queue<?>) reconnectionSignalField.get(rpcClient)).size();
Assert.assertEquals(beforeSize, afterSize);
assertEquals(beforeSize, afterSize);
}
@Test
public void testResolveServerInfo1() throws InvocationTargetException, IllegalAccessException {
Assert.assertEquals(":8848",
((RpcClient.ServerInfo) resolveServerInfoMethod.invoke(rpcClient, "")).getAddress());
Assert.assertEquals("10.10.10.10:8848",
assertEquals("10.10.10.10:8848",
((RpcClient.ServerInfo) resolveServerInfoMethod.invoke(rpcClient, "10.10.10.10::8848")).getAddress());
Assert.assertEquals("10.10.10.10:8848",
assertEquals("10.10.10.10:8848",
((RpcClient.ServerInfo) resolveServerInfoMethod.invoke(rpcClient, "10.10.10.10:8848")).getAddress());
Assert.assertEquals("10.10.10.10:8848", ((RpcClient.ServerInfo) resolveServerInfoMethod.invoke(rpcClient,
"http://10.10.10.10:8848")).getAddress());
Assert.assertEquals("10.10.10.10:8848", ((RpcClient.ServerInfo) resolveServerInfoMethod.invoke(rpcClient,
"http://10.10.10.10::8848")).getAddress());
Assert.assertEquals("10.10.10.10:8848",
assertEquals("10.10.10.10:8848",
((RpcClient.ServerInfo) resolveServerInfoMethod.invoke(rpcClient, "http://10.10.10.10:8848"))
.getAddress());
assertEquals("10.10.10.10:8848",
((RpcClient.ServerInfo) resolveServerInfoMethod.invoke(rpcClient, "http://10.10.10.10::8848"))
.getAddress());
assertEquals("10.10.10.10:8848",
((RpcClient.ServerInfo) resolveServerInfoMethod.invoke(rpcClient, "http://10.10.10.10")).getAddress());
Assert.assertEquals("10.10.10.10:8848", ((RpcClient.ServerInfo) resolveServerInfoMethod.invoke(rpcClient,
"https://10.10.10.10::8848")).getAddress());
assertEquals("10.10.10.10:8848",
((RpcClient.ServerInfo) resolveServerInfoMethod.invoke(rpcClient, "https://10.10.10.10::8848"))
.getAddress());
}
@Test
public void testResolveServerInfo2() throws InvocationTargetException, IllegalAccessException {
System.setProperty("nacos.server.port", "4424");
Assert.assertEquals("10.10.10.10:4424",
assertEquals("10.10.10.10:4424",
((RpcClient.ServerInfo) resolveServerInfoMethod.invoke(rpcClient, "http://10.10.10.10")).getAddress());
}
@ -308,7 +360,7 @@ public class RpcClientTest {
rpcClient.rpcClientStatus.set(RpcClientStatus.RUNNING);
rpcClient.currentConnection = connection;
doReturn(new ErrorResponse()).when(connection).request(any(), anyLong());
rpcClient.request(null, 10000);
}
@ -327,7 +379,7 @@ public class RpcClientTest {
exception = e;
}
Assert.assertEquals(RpcClientStatus.UNHEALTHY, rpcClient.rpcClientStatus.get());
assertEquals(RpcClientStatus.UNHEALTHY, rpcClient.rpcClientStatus.get());
verify(rpcClient).switchServerAsync();
Assert.assertNotNull(exception);
}
@ -349,7 +401,7 @@ public class RpcClientTest {
RequestCallBack<?> requestCallBack = mock(RequestCallBack.class);
doReturn(10000L).when(requestCallBack).getTimeout();
Exception exception = null;
try {
rpcClient.asyncRequest(null, requestCallBack);
} catch (NacosException e) {
@ -359,7 +411,7 @@ public class RpcClientTest {
verify(connection, atLeastOnce()).asyncRequest(any(), any());
verify(rpcClient).switchServerAsyncOnRequestFail();
Assert.assertNotNull(exception);
Assert.assertEquals(RpcClientStatus.UNHEALTHY, rpcClient.rpcClientStatus.get());
assertEquals(RpcClientStatus.UNHEALTHY, rpcClient.rpcClientStatus.get());
}
@Test(expected = NacosException.class)
@ -370,9 +422,10 @@ public class RpcClientTest {
}
@Test
public void testRequestFutureWhenRetryReachMaxRetryTimesThenSwitchServer() throws NacosException, IllegalAccessException {
timeoutMillsField.set(rpcClient, 5000L);
retryTimesField.set(rpcClient, 3);
public void testRequestFutureWhenRetryReachMaxRetryTimesThenSwitchServer()
throws NacosException, IllegalAccessException {
when(rpcClientConfig.timeOutMills()).thenReturn(5000L);
when(rpcClientConfig.retryTimes()).thenReturn(3);
rpcClient.rpcClientStatus.set(RpcClientStatus.RUNNING);
rpcClient.currentConnection = connection;
doThrow(NacosException.class).when(connection).requestFuture(any());
@ -387,22 +440,57 @@ public class RpcClientTest {
verify(connection, times(3)).requestFuture(any());
verify(rpcClient).switchServerAsyncOnRequestFail();
Assert.assertNotNull(exception);
Assert.assertEquals(RpcClientStatus.UNHEALTHY, rpcClient.rpcClientStatus.get());
assertEquals(RpcClientStatus.UNHEALTHY, rpcClient.rpcClientStatus.get());
}
@Test
public void testRpcClientShutdownWhenClientDidntStart() throws NacosException {
RpcClient rpcClient = new RpcClient("test-client") {
RpcClient rpcClient = new RpcClient(new RpcClientConfig() {
@Override
public String name() {
return "test-client";
}
@Override
public int retryTimes() {
return 3;
}
@Override
public long timeOutMills() {
return 3000L;
}
@Override
public long connectionKeepAlive() {
return 5000L;
}
@Override
public int healthCheckRetryTimes() {
return 1;
}
@Override
public long healthCheckTimeOut() {
return 3000L;
}
@Override
public Map<String, String> labels() {
return new HashMap<>();
}
}) {
@Override
public ConnectionType getConnectionType() {
return null;
}
@Override
public int rpcPortOffset() {
return 0;
}
@Override
public Connection connectToServer(ServerInfo serverInfo) throws Exception {
return null;
@ -411,4 +499,140 @@ public class RpcClientTest {
rpcClient.shutdown();
}
}
@Test
public void testHealthCheck() throws IllegalAccessException, NacosException {
Random random = new Random();
int retry = random.nextInt(10);
when(rpcClientConfig.healthCheckRetryTimes()).thenReturn(retry);
rpcClient.rpcClientStatus.set(RpcClientStatus.RUNNING);
rpcClient.currentConnection = connection;
doThrow(new NacosException()).when(connection).request(any(), anyLong());
try {
healthCheck.invoke(rpcClient);
} catch (InvocationTargetException e) {
e.printStackTrace();
}
verify(connection, times(retry + 1)).request(any(), anyLong());
}
@Test
public void testNextRpcServerForIpv4WithPort() {
RpcClient rpcClient = buildTestNextRpcServerClient();
rpcClient.serverListFactory(serverListFactory);
when(serverListFactory.genNextServer()).thenReturn("127.0.0.1:7777");
RpcClient.ServerInfo actual = rpcClient.nextRpcServer();
assertEquals("127.0.0.1:7777", actual.getAddress());
assertEquals("127.0.0.1", actual.getServerIp());
assertEquals(7777, actual.getServerPort());
}
@Test
public void testNextRpcServerForIpv4WithoutPort() {
RpcClient rpcClient = buildTestNextRpcServerClient();
rpcClient.serverListFactory(serverListFactory);
when(serverListFactory.genNextServer()).thenReturn("127.0.0.1");
RpcClient.ServerInfo actual = rpcClient.nextRpcServer();
assertEquals("127.0.0.1:8848", actual.getAddress());
assertEquals("127.0.0.1", actual.getServerIp());
assertEquals(8848, actual.getServerPort());
}
@Test
public void testNextRpcServerForIpv6WithPort() {
RpcClient rpcClient = buildTestNextRpcServerClient();
rpcClient.serverListFactory(serverListFactory);
when(serverListFactory.genNextServer()).thenReturn("[fe80::35ba:6827:c5ff:d161%11]:7777");
RpcClient.ServerInfo actual = rpcClient.nextRpcServer();
assertEquals("[fe80::35ba:6827:c5ff:d161%11]:7777", actual.getAddress());
assertEquals("[fe80::35ba:6827:c5ff:d161%11]", actual.getServerIp());
assertEquals(7777, actual.getServerPort());
}
@Test
public void testNextRpcServerForIpv6WithoutPort() {
RpcClient rpcClient = buildTestNextRpcServerClient();
rpcClient.serverListFactory(serverListFactory);
when(serverListFactory.genNextServer()).thenReturn("[fe80::35ba:6827:c5ff:d161%11]");
RpcClient.ServerInfo actual = rpcClient.nextRpcServer();
assertEquals("[fe80::35ba:6827:c5ff:d161%11]:8848", actual.getAddress());
assertEquals("[fe80::35ba:6827:c5ff:d161%11]", actual.getServerIp());
assertEquals(8848, actual.getServerPort());
}
@Test
public void testNextRpcServerForDomainWithPort() {
RpcClient rpcClient = buildTestNextRpcServerClient();
rpcClient.serverListFactory(serverListFactory);
when(serverListFactory.genNextServer()).thenReturn("nacos.io:7777");
RpcClient.ServerInfo actual = rpcClient.nextRpcServer();
assertEquals("nacos.io:7777", actual.getAddress());
assertEquals("nacos.io", actual.getServerIp());
assertEquals(7777, actual.getServerPort());
}
@Test
public void testNextRpcServerForDomainWithoutPort() {
RpcClient rpcClient = buildTestNextRpcServerClient();
rpcClient.serverListFactory(serverListFactory);
when(serverListFactory.genNextServer()).thenReturn("nacos.io");
RpcClient.ServerInfo actual = rpcClient.nextRpcServer();
assertEquals("nacos.io:8848", actual.getAddress());
assertEquals("nacos.io", actual.getServerIp());
assertEquals(8848, actual.getServerPort());
}
@Test
public void testNextRpcServerForLocalhostWithPort() {
RpcClient rpcClient = buildTestNextRpcServerClient();
rpcClient.serverListFactory(serverListFactory);
when(serverListFactory.genNextServer()).thenReturn("localhost:7777");
RpcClient.ServerInfo actual = rpcClient.nextRpcServer();
assertEquals("localhost:7777", actual.getAddress());
assertEquals("localhost", actual.getServerIp());
assertEquals(7777, actual.getServerPort());
}
@Test
public void testNextRpcServerForLocalhostWithoutPort() {
RpcClient rpcClient = buildTestNextRpcServerClient();
rpcClient.serverListFactory(serverListFactory);
when(serverListFactory.genNextServer()).thenReturn("localhost");
RpcClient.ServerInfo actual = rpcClient.nextRpcServer();
assertEquals("localhost:8848", actual.getAddress());
assertEquals("localhost", actual.getServerIp());
assertEquals(8848, actual.getServerPort());
}
@Test(expected = IllegalArgumentException.class)
public void testNextRpcServerForEmpty() {
RpcClient rpcClient = buildTestNextRpcServerClient();
rpcClient.serverListFactory(serverListFactory);
when(serverListFactory.genNextServer()).thenReturn("");
rpcClient.nextRpcServer();
}
private RpcClient buildTestNextRpcServerClient() {
return new RpcClient(DefaultGrpcClientConfig.newBuilder().build()) {
@Override
public ConnectionType getConnectionType() {
return null;
}
@Override
public int rpcPortOffset() {
return 0;
}
@Override
public Connection connectToServer(ServerInfo serverInfo) throws Exception {
return null;
}
@Override
public ServerInfo nextRpcServer() {
return super.nextRpcServer();
}
};
}
}

View File

@ -33,38 +33,41 @@ import static org.mockito.Mockito.spy;
@RunWith(MockitoJUnitRunner.class)
public class GrpcClientTest {
GrpcClient grpcClient;
Method createNewManagedChannelMethod;
Method createNewChannelStubMethod;
ManagedChannel managedChannel;
RpcClient.ServerInfo serverInfo;
@Before
public void setUp() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
grpcClient = spy(new GrpcClient("testClient") {
GrpcClientConfig clientConfig = DefaultGrpcClientConfig.newBuilder().setName("testClient").build();
grpcClient = spy(new GrpcClient(clientConfig) {
@Override
public int rpcPortOffset() {
return 1000;
}
});
RpcClient.ServerInfo serverInfo = spy(new RpcClient.ServerInfo("10.10.10.10", 8848));
createNewManagedChannelMethod = GrpcClient.class.getDeclaredMethod("createNewManagedChannel", String.class, int.class);
createNewManagedChannelMethod = GrpcClient.class.getDeclaredMethod("createNewManagedChannel", String.class,
int.class);
createNewManagedChannelMethod.setAccessible(true);
int port = serverInfo.getServerPort() + grpcClient.rpcPortOffset();
managedChannel = (ManagedChannel) createNewManagedChannelMethod.invoke(grpcClient, serverInfo.getServerIp(), port);
managedChannel = (ManagedChannel) createNewManagedChannelMethod.invoke(grpcClient, serverInfo.getServerIp(),
port);
}
@Test
public void testCreateNewManagedChannel() throws InvocationTargetException, IllegalAccessException {
GrpcConnection grpcConnection = new GrpcConnection(serverInfo, null);
grpcConnection.setChannel(managedChannel);
}
@Test
public void createNewChannelStub() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
createNewChannelStubMethod = GrpcClient.class.getDeclaredMethod("createNewChannelStub", ManagedChannel.class);
@ -72,10 +75,10 @@ public class GrpcClientTest {
Object invoke = createNewChannelStubMethod.invoke(grpcClient, managedChannel);
Assert.assertTrue(invoke instanceof RequestGrpc.RequestFutureStub);
}
@After
public void close() {
managedChannel.shutdownNow();
}
}

View File

@ -0,0 +1,41 @@
/*
* 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.common.remote.client.grpc;
import org.junit.Test;
import java.lang.reflect.Field;
import static org.junit.Assert.assertEquals;
public class GrpcConstantsTest {
@Test
public void testGetRpcParams() {
Class clazz = GrpcConstants.class;
Field[] declaredFields = clazz.getDeclaredFields();
int i = 0;
for (Field declaredField : declaredFields) {
declaredField.setAccessible(true);
if (declaredField.getType().equals(String.class) && null != declaredField.getAnnotation(
GrpcConstants.GRpcConfigLabel.class)) {
i++;
}
}
assertEquals(i, GrpcConstants.getRpcParams().size());
}
}

View File

@ -17,12 +17,12 @@
package com.alibaba.nacos.common.utils;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.ConcurrentModificationException;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* ConcurrentHashSet Test.
@ -32,108 +32,200 @@ import java.util.Set;
*/
public class ConcurrentHashSetTest {
Set<Integer> concurrentHashSet;
@Before
public void setUp() {
concurrentHashSet = new ConcurrentHashSet<>();
concurrentHashSet.add(1);
concurrentHashSet.add(2);
concurrentHashSet.add(3);
concurrentHashSet.add(4);
concurrentHashSet.add(5);
@Test
public void testBasicOps() {
Set<Integer> set = new ConcurrentHashSet<>();
// addition
Assert.assertTrue(set.add(0));
Assert.assertTrue(set.add(1));
Assert.assertTrue(set.contains(0));
Assert.assertTrue(set.contains(1));
Assert.assertFalse(set.contains(-1));
Assert.assertEquals(2, set.size());
// iter
for (int i : set) {
Assert.assertTrue(i == 0 || i == 1);
}
// removal
Assert.assertTrue(set.remove(0));
Assert.assertFalse(set.remove(0));
Assert.assertFalse(set.contains(0));
Assert.assertTrue(set.contains(1));
Assert.assertEquals(1, set.size());
// clear
Assert.assertFalse(set.isEmpty());
set.clear();
Assert.assertEquals(0, set.size());
Assert.assertTrue(set.isEmpty());
}
@Test
public void testMultiThread() throws Exception {
int count = 5;
SetMultiThreadChecker hashSetChecker = new SetMultiThreadChecker(new HashSet<>());
hashSetChecker.start();
while (!hashSetChecker.hasConcurrentError() && hashSetChecker.isRunning()) {
TimeUnit.SECONDS.sleep(1);
if (count <= 0) {
hashSetChecker.stop();
}
count--;
}
Assert.assertTrue(hashSetChecker.hasConcurrentError());
count = 5;
SetMultiThreadChecker concurrentSetChecker = new SetMultiThreadChecker(new ConcurrentHashSet<>());
concurrentSetChecker.start();
while (!concurrentSetChecker.hasConcurrentError() && concurrentSetChecker.isRunning()) {
TimeUnit.SECONDS.sleep(1);
if (count == 0) {
concurrentSetChecker.stop();
}
count--;
}
Assert.assertFalse(concurrentSetChecker.hasConcurrentError());
}
static class SetMultiThreadChecker {
private final AddDataThread addThread;
private final DeleteDataThread deleteThread;
private final IteratorThread iteratorThread;
public SetMultiThreadChecker(Set<Integer> setToCheck) {
for (int i = 0; i < 1000; i++) {
setToCheck.add(i);
}
this.addThread = new AddDataThread(setToCheck);
this.deleteThread = new DeleteDataThread(setToCheck);
this.iteratorThread = new IteratorThread(setToCheck);
}
public void start() {
new Thread(addThread).start();
new Thread(deleteThread).start();
new Thread(iteratorThread).start();
}
public boolean hasConcurrentError() {
return addThread.hasConcurrentError() || deleteThread.hasConcurrentError() || iteratorThread.hasConcurrentError();
}
public boolean isRunning() {
return addThread.isRunning() || deleteThread.isRunning() || iteratorThread.isRunning();
}
public void stop() {
addThread.stop();
deleteThread.stop();
iteratorThread.stop();
}
}
@Test
public void size() {
Assert.assertEquals(concurrentHashSet.size(), 5);
}
abstract static class ConcurrentCheckThread implements Runnable {
@Test
public void contains() {
Assert.assertTrue(concurrentHashSet.contains(1));
}
protected final Set<Integer> hashSet;
@Test
public void testMultithreaded() {
try {
concurrentHashSet = new HashSet<>();
executeThread();
} catch (Exception e) {
Assert.assertTrue(e instanceof ConcurrentModificationException);
protected boolean concurrentError = false;
protected boolean finish = false;
public ConcurrentCheckThread(Set<Integer> hashSet) {
this.hashSet = hashSet;
}
public boolean hasConcurrentError() {
return concurrentError;
}
try {
concurrentHashSet = new ConcurrentHashSet<>();
executeThread();
} catch (Exception e) {
Assert.assertNull(e);
}
}
/**
* execute muti thread.
*/
public void executeThread() throws Exception {
for (int i = 0; i < 1000; i++) {
concurrentHashSet.add(i);
public void stop() {
finish = true;
}
new Thread(new AddDataThread(concurrentHashSet)).start();
new Thread(new DeleteDataThread(concurrentHashSet)).start();
new Thread(new IteratorThread(concurrentHashSet)).start();
public boolean isRunning() {
return !finish;
}
@Override
public void run() {
try {
while (isRunning()) {
process();
}
} catch (ConcurrentModificationException e) {
concurrentError = true;
} finally {
finish = true;
}
}
protected abstract void process();
}
//add data thread
static class AddDataThread implements Runnable {
Set<Integer> hashSet;
static class AddDataThread extends ConcurrentCheckThread implements Runnable {
public AddDataThread(Set<Integer> hashSet) {
this.hashSet = hashSet;
super(hashSet);
}
@Override
public void run() {
while (true) {
int random = new Random().nextInt();
hashSet.add(random);
}
protected void process() {
int random = new Random().nextInt(1000);
hashSet.add(random);
}
}
// delete data thread
static class DeleteDataThread implements Runnable {
Set<Integer> hashSet;
static class DeleteDataThread extends ConcurrentCheckThread implements Runnable {
public DeleteDataThread(Set<Integer> hashSet) {
this.hashSet = hashSet;
super(hashSet);
}
@Override
public void run() {
protected void process() {
int random = new Random().nextInt(1000);
while (true) {
hashSet.remove(random);
}
hashSet.remove(random);
}
}
static class IteratorThread implements Runnable {
Set<Integer> hashSet;
static class IteratorThread extends ConcurrentCheckThread implements Runnable {
public IteratorThread(Set<Integer> hashSet) {
this.hashSet = hashSet;
super(hashSet);
}
@Override
public void run() {
System.out.println("start -- hashSet.size() : " + hashSet.size());
for (Integer str : hashSet) {
System.out.println("value : " + str);
Integer f = null;
try {
while (isRunning()) {
for (Integer i : hashSet) {
f = i;
}
}
} catch (ConcurrentModificationException e) {
concurrentError = true;
} finally {
finish = true;
}
System.out.println("finished at " + f);
System.out.println("end -- hashSet.size() : " + hashSet.size());
}
@Override
protected void process() {
}
}
}

View File

@ -23,6 +23,7 @@ import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.type.TypeReference;
@ -474,6 +475,7 @@ public class JacksonUtilsTest {
Assert.assertEquals(999, restResult.getData().get("integer"));
}
@JsonPropertyOrder({ "aLong", "aInteger", "aBoolean"})
static class TestOfAtomicObject {
public AtomicLong aLong = new AtomicLong(0);
@ -558,6 +560,7 @@ public class JacksonUtilsTest {
}
}
@JsonPropertyOrder({ "value", "key" })
static class TestOfGetter {
public String getKey() {
@ -749,4 +752,4 @@ public class JacksonUtilsTest {
return result;
}
}
}
}

View File

@ -117,6 +117,10 @@
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-datasource-plugin</artifactId>
</dependency>
</dependencies>
<build>
<plugins>

View File

@ -37,6 +37,11 @@ public class Constants {
*/
public static final String BASE_DIR = "config-data";
/**
* The derby base dir.
*/
public static final String DERBY_BASE_DIR = "derby-data";
/**
* Back up file directory in server side.
*
@ -111,6 +116,8 @@ public class Constants {
public static final String BASE_PATH = "/v1/cs";
public static final String BASE_V2_PATH = "/v2/cs";
public static final String OPS_CONTROLLER_PATH = BASE_PATH + "/ops";
public static final String CAPACITY_CONTROLLER_PATH = BASE_PATH + "/capacity";
@ -119,10 +126,14 @@ public class Constants {
public static final String CONFIG_CONTROLLER_PATH = BASE_PATH + "/configs";
public static final String CONFIG_CONTROLLER_V2_PATH = BASE_V2_PATH + "/config";
public static final String HEALTH_CONTROLLER_PATH = BASE_PATH + "/health";
public static final String HISTORY_CONTROLLER_PATH = BASE_PATH + "/history";
public static final String HISTORY_CONTROLLER_V2_PATH = BASE_V2_PATH + "/history";
public static final String LISTENER_CONTROLLER_PATH = BASE_PATH + "/listener";
public static final String NAMESPACE_CONTROLLER_PATH = BASE_PATH + "/namespaces";

View File

@ -22,7 +22,6 @@ import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.common.model.RestResultUtils;
import com.alibaba.nacos.common.utils.DateFormatUtils;
import com.alibaba.nacos.common.utils.MapUtil;
import com.alibaba.nacos.common.utils.NamespaceUtil;
import com.alibaba.nacos.common.utils.Pair;
import com.alibaba.nacos.common.utils.StringUtils;
@ -38,10 +37,12 @@ import com.alibaba.nacos.config.server.model.Page;
import com.alibaba.nacos.config.server.model.SameConfigPolicy;
import com.alibaba.nacos.config.server.model.SampleResult;
import com.alibaba.nacos.config.server.model.event.ConfigDataChangeEvent;
import com.alibaba.nacos.config.server.model.ConfigRequestInfo;
import com.alibaba.nacos.config.server.model.form.ConfigForm;
import com.alibaba.nacos.config.server.monitor.MetricsMonitor;
import com.alibaba.nacos.config.server.result.code.ResultCodeEnum;
import com.alibaba.nacos.config.server.service.AggrWhitelist;
import com.alibaba.nacos.config.server.service.ConfigChangePublisher;
import com.alibaba.nacos.config.server.service.ConfigOperationService;
import com.alibaba.nacos.config.server.service.ConfigSubService;
import com.alibaba.nacos.config.server.service.repository.PersistService;
import com.alibaba.nacos.config.server.service.trace.ConfigTraceService;
@ -108,12 +109,15 @@ public class ConfigController {
private final PersistService persistService;
private final ConfigOperationService configOperationService;
private final ConfigSubService configSubService;
public ConfigController(ConfigServletInner inner, PersistService persistService,
public ConfigController(ConfigServletInner inner, PersistService persistService, ConfigOperationService configOperationService,
ConfigSubService configSubService) {
this.inner = inner;
this.persistService = persistService;
this.configOperationService = configOperationService;
this.configSubService = configSubService;
}
@ -142,16 +146,6 @@ public class ConfigController {
@RequestParam(value = "type", required = false) String type,
@RequestParam(value = "schema", required = false) String schema) throws NacosException {
final String srcIp = RequestUtil.getRemoteIp(request);
final String requestIpApp = RequestUtil.getAppName(request);
if (StringUtils.isBlank(srcUser)) {
srcUser = RequestUtil.getSrcUserName(request);
}
//check type
if (!ConfigType.isValidType(type)) {
type = ConfigType.getDefaultType().getType();
}
// encrypted
Pair<String, String> pair = EncryptionHandler.encryptHandler(dataId, content);
content = pair.getSecond();
@ -160,47 +154,37 @@ public class ConfigController {
ParamUtils.checkTenant(tenant);
ParamUtils.checkParam(dataId, group, "datumId", content);
ParamUtils.checkParam(tag);
Map<String, Object> configAdvanceInfo = new HashMap<>(10);
MapUtil.putIfValNoNull(configAdvanceInfo, "config_tags", configTags);
MapUtil.putIfValNoNull(configAdvanceInfo, "desc", desc);
MapUtil.putIfValNoNull(configAdvanceInfo, "use", use);
MapUtil.putIfValNoNull(configAdvanceInfo, "effect", effect);
MapUtil.putIfValNoNull(configAdvanceInfo, "type", type);
MapUtil.putIfValNoNull(configAdvanceInfo, "schema", schema);
ParamUtils.checkParam(configAdvanceInfo);
if (AggrWhitelist.isAggrDataId(dataId)) {
LOGGER.warn("[aggr-conflict] {} attempt to publish single data, {}, {}", RequestUtil.getRemoteIp(request),
dataId, group);
throw new NacosException(NacosException.NO_RIGHT, "dataId:" + dataId + " is aggr");
ConfigForm configForm = new ConfigForm();
configForm.setDataId(dataId);
configForm.setGroup(group);
configForm.setNamespaceId(tenant);
configForm.setContent(content);
configForm.setTag(tag);
configForm.setAppName(appName);
configForm.setSrcUser(srcUser);
configForm.setConfigTags(configTags);
configForm.setDesc(desc);
configForm.setUse(use);
configForm.setEffect(effect);
configForm.setType(type);
configForm.setSchema(schema);
if (StringUtils.isBlank(srcUser)) {
configForm.setSrcUser(RequestUtil.getSrcUserName(request));
}
final Timestamp time = TimeUtils.getCurrentTime();
String betaIps = request.getHeader("betaIps");
ConfigInfo configInfo = new ConfigInfo(dataId, group, tenant, appName, content);
configInfo.setType(type);
if (!ConfigType.isValidType(type)) {
configForm.setType(ConfigType.getDefaultType().getType());
}
ConfigRequestInfo configRequestInfo = new ConfigRequestInfo();
configRequestInfo.setSrcIp(RequestUtil.getRemoteIp(request));
configRequestInfo.setRequestIpApp(RequestUtil.getAppName(request));
configRequestInfo.setBetaIps(request.getHeader("betaIps"));
String encryptedDataKey = pair.getFirst();
configInfo.setEncryptedDataKey(encryptedDataKey);
if (StringUtils.isBlank(betaIps)) {
if (StringUtils.isBlank(tag)) {
persistService.insertOrUpdate(srcIp, srcUser, configInfo, time, configAdvanceInfo, false);
ConfigChangePublisher.notifyConfigChange(
new ConfigDataChangeEvent(false, dataId, group, tenant, time.getTime()));
} else {
persistService.insertOrUpdateTag(configInfo, tag, srcIp, srcUser, time, false);
ConfigChangePublisher.notifyConfigChange(
new ConfigDataChangeEvent(false, dataId, group, tenant, tag, time.getTime()));
}
} else {
// beta publish
configInfo.setEncryptedDataKey(encryptedDataKey);
persistService.insertOrUpdateBeta(configInfo, betaIps, srcIp, srcUser, time, false);
ConfigChangePublisher.notifyConfigChange(
new ConfigDataChangeEvent(true, dataId, group, tenant, time.getTime()));
}
ConfigTraceService.logPersistenceEvent(dataId, group, tenant, requestIpApp, time.getTime(),
InetUtils.getSelfIP(), ConfigTraceService.PERSISTENCE_EVENT_PUB, content);
return true;
return configOperationService.publishConfig(configForm, configRequestInfo, encryptedDataKey);
}
/**
@ -276,19 +260,11 @@ public class ConfigController {
ParamUtils.checkTenant(tenant);
ParamUtils.checkParam(dataId, group, "datumId", "rm");
ParamUtils.checkParam(tag);
String clientIp = RequestUtil.getRemoteIp(request);
String srcUser = RequestUtil.getSrcUserName(request);
if (StringUtils.isBlank(tag)) {
persistService.removeConfigInfo(dataId, group, tenant, clientIp, srcUser);
} else {
persistService.removeConfigInfoTag(dataId, group, tenant, tag, clientIp, srcUser);
}
final Timestamp time = TimeUtils.getCurrentTime();
ConfigTraceService.logPersistenceEvent(dataId, group, tenant, null, time.getTime(), clientIp,
ConfigTraceService.PERSISTENCE_EVENT_REMOVE, null);
ConfigChangePublisher.notifyConfigChange(
new ConfigDataChangeEvent(false, dataId, group, tenant, tag, time.getTime()));
return true;
return configOperationService.deleteConfig(dataId, group, tenant, tag, clientIp, srcUser);
}
/**
@ -475,10 +451,10 @@ public class ConfigController {
Pair<String, String> pair = EncryptionHandler.decryptHandler(dataId, encryptedDataKey, ci.getContent());
ci.setContent(pair.getSecond());
}
return RestResultUtils.success("stop beta ok", ci);
return RestResultUtils.success("query beta ok", ci);
} catch (Throwable e) {
LOGGER.error("remove beta data error", e);
return RestResultUtils.failed("remove beta data error");
LOGGER.error("query beta data error", e);
return RestResultUtils.failed("query beta data error");
}
}

View File

@ -16,10 +16,14 @@
package com.alibaba.nacos.config.server.controller;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.common.constant.HttpHeaderConsts;
import com.alibaba.nacos.common.http.param.MediaType;
import com.alibaba.nacos.common.utils.IoUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.common.utils.Pair;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.config.server.constant.Constants;
import com.alibaba.nacos.config.server.enums.FileTypeEnum;
import com.alibaba.nacos.config.server.model.CacheItem;
@ -37,6 +41,8 @@ import com.alibaba.nacos.config.server.utils.Protocol;
import com.alibaba.nacos.config.server.utils.RequestUtil;
import com.alibaba.nacos.config.server.utils.TimeUtils;
import com.alibaba.nacos.plugin.encryption.handler.EncryptionHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.servlet.ServletException;
@ -65,6 +71,8 @@ public class ConfigServletInner {
private static final int START_LONG_POLLING_VERSION_NUM = 204;
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigServletInner.class);
private final LongPollingService longPollingService;
private final PersistService persistService;
@ -116,16 +124,29 @@ public class ConfigServletInner {
}
/**
* Execute to get config API.
* Execute to get config [API V1].
*/
public String doGetConfig(HttpServletRequest request, HttpServletResponse response, String dataId, String group,
String tenant, String tag, String isNotify, String clientIp) throws IOException, ServletException {
return doGetConfig(request, response, dataId, group, tenant, tag, isNotify, clientIp, false);
}
/**
* Execute to get config [API V1] or [API V2].
*/
public String doGetConfig(HttpServletRequest request, HttpServletResponse response, String dataId, String group,
String tenant, String tag, String isNotify, String clientIp, boolean isV2)
throws IOException, ServletException {
boolean notify = false;
if (StringUtils.isNotBlank(isNotify)) {
notify = Boolean.parseBoolean(isNotify);
}
if (isV2) {
response.setHeader(HttpHeaderConsts.CONTENT_TYPE, MediaType.APPLICATION_JSON);
}
final String groupKey = GroupKey2.getKey(dataId, group, tenant);
String autoTag = request.getHeader("Vipserver-Tag");
@ -153,6 +174,10 @@ public class ConfigServletInner {
String contentTypeHeader = fileTypeEnum.getContentType();
response.setHeader(HttpHeaderConsts.CONTENT_TYPE, contentTypeHeader);
if (isV2) {
response.setHeader(HttpHeaderConsts.CONTENT_TYPE, MediaType.APPLICATION_JSON);
}
File file = null;
ConfigInfoBase configInfoBase = null;
PrintWriter out;
@ -200,7 +225,7 @@ public class ConfigServletInner {
// no data",
// new Object[]{clientIp, groupKey});
return get404Result(response);
return get404Result(response, isV2);
}
isSli = true;
}
@ -229,9 +254,7 @@ public class ConfigServletInner {
// no data",
// new Object[]{clientIp, groupKey});
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
response.getWriter().println("config data not exist");
return HttpServletResponse.SC_NOT_FOUND + "";
return get404Result(response, isV2);
}
}
}
@ -250,10 +273,14 @@ public class ConfigServletInner {
}
if (PropertyUtil.isDirectRead()) {
Pair<String, String> pair = EncryptionHandler.decryptHandler(dataId,
configInfoBase.getEncryptedDataKey(), configInfoBase.getContent());
Pair<String, String> pair = EncryptionHandler
.decryptHandler(dataId, configInfoBase.getEncryptedDataKey(), configInfoBase.getContent());
out = response.getWriter();
out.print(pair.getSecond());
if (isV2) {
out.print(JacksonUtils.toJson(Result.success(pair.getSecond())));
} else {
out.print(pair.getSecond());
}
out.flush();
out.close();
} else {
@ -262,7 +289,11 @@ public class ConfigServletInner {
Pair<String, String> pair = EncryptionHandler.decryptHandler(dataId, encryptedDataKey, fileContent);
String decryptContent = pair.getSecond();
out = response.getWriter();
out.print(decryptContent);
if (isV2) {
out.print(JacksonUtils.toJson(Result.success(decryptContent)));
} else {
out.print(decryptContent);
}
out.flush();
out.close();
}
@ -290,15 +321,12 @@ public class ConfigServletInner {
.logPullEvent(dataId, group, tenant, requestIpApp, -1, ConfigTraceService.PULL_EVENT_NOTFOUND, -1,
requestIp, notify && isSli);
return get404Result(response);
return get404Result(response, isV2);
} else {
PULL_LOG.info("[client-get] clientIp={}, {}, get data during dump", clientIp, groupKey);
response.setStatus(HttpServletResponse.SC_CONFLICT);
response.getWriter().println("requested file is being modified, please try later.");
return HttpServletResponse.SC_CONFLICT + "";
return get409Result(response, isV2);
}
@ -309,12 +337,29 @@ public class ConfigServletInner {
ConfigCacheService.releaseReadLock(groupKey);
}
private String get404Result(HttpServletResponse response) throws IOException {
private String get404Result(HttpServletResponse response, boolean isV2) throws IOException {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
response.getWriter().println("config data not exist");
PrintWriter writer = response.getWriter();
if (isV2) {
writer.println(JacksonUtils.toJson(Result.failure(ErrorCode.RESOURCE_NOT_FOUND, "config data not exist")));
} else {
writer.println("config data not exist");
}
return HttpServletResponse.SC_NOT_FOUND + "";
}
private String get409Result(HttpServletResponse response, boolean isV2) throws IOException {
response.setStatus(HttpServletResponse.SC_CONFLICT);
PrintWriter writer = response.getWriter();
if (isV2) {
writer.println(JacksonUtils.toJson(Result
.failure(ErrorCode.RESOURCE_CONFLICT, "requested file is being modified, please try later.")));
} else {
writer.println("requested file is being modified, please try later.");
}
return HttpServletResponse.SC_CONFLICT + "";
}
/**
* Try to add read lock.
*

View File

@ -18,18 +18,16 @@ package com.alibaba.nacos.config.server.controller;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.common.utils.NamespaceUtil;
import com.alibaba.nacos.common.utils.Pair;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.config.server.constant.Constants;
import com.alibaba.nacos.config.server.model.ConfigHistoryInfo;
import com.alibaba.nacos.config.server.model.ConfigInfoWrapper;
import com.alibaba.nacos.config.server.model.Page;
import com.alibaba.nacos.config.server.service.repository.PersistService;
import com.alibaba.nacos.config.server.service.HistoryService;
import com.alibaba.nacos.config.server.utils.ParamUtils;
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
import com.alibaba.nacos.plugin.auth.constant.SignType;
import com.alibaba.nacos.plugin.auth.exception.AccessException;
import com.alibaba.nacos.plugin.encryption.handler.EncryptionHandler;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@ -37,7 +35,6 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Objects;
/**
* History management controller.
@ -48,10 +45,10 @@ import java.util.Objects;
@RequestMapping(Constants.HISTORY_CONTROLLER_PATH)
public class HistoryController {
private final PersistService persistService;
private final HistoryService historyService;
public HistoryController(PersistService persistService) {
this.persistService = persistService;
public HistoryController(HistoryService historyService) {
this.historyService = historyService;
}
/**
@ -79,7 +76,7 @@ public class HistoryController {
pageSize = null == pageSize ? 100 : pageSize;
pageSize = Math.min(500, pageSize);
// configInfoBase has no appName field.
return persistService.findConfigHistory(dataId, group, tenant, pageNo, pageSize);
return historyService.listConfigHistory(dataId, group, tenant, pageNo, pageSize);
}
/**
@ -98,38 +95,7 @@ public class HistoryController {
@RequestParam("group") String group,
@RequestParam(value = "tenant", required = false, defaultValue = StringUtils.EMPTY) String tenant,
@RequestParam("nid") Long nid) throws AccessException {
ConfigHistoryInfo configHistoryInfo = persistService.detailConfigHistory(nid);
if (Objects.isNull(configHistoryInfo)) {
return null;
}
// check if history config match the input
checkHistoryInfoPermission(configHistoryInfo, dataId, group, tenant);
String encryptedDataKey = configHistoryInfo.getEncryptedDataKey();
Pair<String, String> pair = EncryptionHandler.decryptHandler(dataId, encryptedDataKey,
configHistoryInfo.getContent());
configHistoryInfo.setContent(pair.getSecond());
return configHistoryInfo;
}
/**
* Check if the input dataId,group and tenant match the history config.
*
* @param configHistoryInfo history config.
* @param dataId dataId
* @param group group
* @param tenant tenant
* @throws AccessException not match exception.
* @since 2.0.3
*/
private void checkHistoryInfoPermission(ConfigHistoryInfo configHistoryInfo, String dataId, String group,
String tenant) throws AccessException {
if (!Objects.equals(configHistoryInfo.getDataId(), dataId)
|| !Objects.equals(configHistoryInfo.getGroup(), group)
|| !Objects.equals(configHistoryInfo.getTenant(), tenant)) {
throw new AccessException("Please check dataId, group or tenant.");
}
return historyService.getConfigHistoryInfo(dataId, group, tenant, nid);
}
/**
@ -149,13 +115,7 @@ public class HistoryController {
@RequestParam("group") String group,
@RequestParam(value = "tenant", required = false, defaultValue = StringUtils.EMPTY) String tenant,
@RequestParam("id") Long id) throws AccessException {
ConfigHistoryInfo configHistoryInfo = persistService.detailPreviousConfigHistory(id);
if (Objects.isNull(configHistoryInfo)) {
return null;
}
// check if history config match the input
checkHistoryInfoPermission(configHistoryInfo, dataId, group, tenant);
return configHistoryInfo;
return historyService.getPreviousConfigHistoryInfo(dataId, group, tenant, id);
}
/**
@ -171,7 +131,7 @@ public class HistoryController {
// check tenant
ParamUtils.checkTenant(tenant);
tenant = NamespaceUtil.processNamespaceParameter(tenant);
return persistService.queryConfigInfoByNamespace(tenant);
return historyService.getConfigListByNamespace(tenant);
}
}

View File

@ -0,0 +1,151 @@
/*
* 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.config.server.controller.v2;
import com.alibaba.nacos.api.annotation.NacosApi;
import com.alibaba.nacos.api.config.ConfigType;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.common.utils.NamespaceUtil;
import com.alibaba.nacos.common.utils.Pair;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.config.server.constant.Constants;
import com.alibaba.nacos.config.server.controller.ConfigServletInner;
import com.alibaba.nacos.config.server.model.ConfigRequestInfo;
import com.alibaba.nacos.config.server.model.form.ConfigForm;
import com.alibaba.nacos.config.server.service.ConfigOperationService;
import com.alibaba.nacos.config.server.utils.ParamUtils;
import com.alibaba.nacos.config.server.utils.RequestUtil;
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
import com.alibaba.nacos.plugin.auth.constant.SignType;
import com.alibaba.nacos.plugin.encryption.handler.EncryptionHandler;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Special controller v2 for soft load client to publish data.
*
* @author dongyafei
* @date 2022/7/22
*/
@NacosApi
@RestController
@RequestMapping(Constants.CONFIG_CONTROLLER_V2_PATH)
public class ConfigControllerV2 {
private final ConfigServletInner inner;
private final ConfigOperationService configOperationService;
public ConfigControllerV2(ConfigServletInner inner, ConfigOperationService configOperationService) {
this.inner = inner;
this.configOperationService = configOperationService;
}
/**
* Get configure board information fail.
*
* @throws ServletException ServletException.
* @throws IOException IOException.
* @throws NacosApiException NacosApiException.
*/
@GetMapping
@Secured(action = ActionTypes.READ, signType = SignType.CONFIG)
public void getConfig(HttpServletRequest request, HttpServletResponse response,
@RequestParam("dataId") String dataId, @RequestParam("group") String group,
@RequestParam(value = "namespaceId", required = false, defaultValue = StringUtils.EMPTY) String namespaceId,
@RequestParam(value = "tag", required = false) String tag)
throws NacosException, IOException, ServletException {
// check namespaceId
ParamUtils.checkTenantV2(namespaceId);
namespaceId = NamespaceUtil.processNamespaceParameter(namespaceId);
// check params
ParamUtils.checkParam(dataId, group, "datumId", "content");
ParamUtils.checkParamV2(tag);
final String clientIp = RequestUtil.getRemoteIp(request);
String isNotify = request.getHeader("notify");
inner.doGetConfig(request, response, dataId, group, namespaceId, tag, isNotify, clientIp, true);
}
/**
* Adds or updates non-aggregated data.
*
* @throws NacosException NacosException.
*/
@PostMapping()
@Secured(action = ActionTypes.WRITE, signType = SignType.CONFIG)
public Result<Boolean> publishConfig(ConfigForm configForm, HttpServletRequest request) throws NacosException {
// check required field
configForm.validate();
// encrypted
Pair<String, String> pair = EncryptionHandler.encryptHandler(configForm.getDataId(), configForm.getContent());
configForm.setContent(pair.getSecond());
// check param
ParamUtils.checkTenantV2(configForm.getNamespaceId());
ParamUtils.checkParam(configForm.getDataId(), configForm.getGroup(), "datumId", configForm.getContent());
ParamUtils.checkParamV2(configForm.getTag());
if (StringUtils.isBlank(configForm.getSrcUser())) {
configForm.setSrcUser(RequestUtil.getSrcUserName(request));
}
if (!ConfigType.isValidType(configForm.getType())) {
configForm.setType(ConfigType.getDefaultType().getType());
}
ConfigRequestInfo configRequestInfo = new ConfigRequestInfo();
configRequestInfo.setSrcIp(RequestUtil.getRemoteIp(request));
configRequestInfo.setRequestIpApp(RequestUtil.getAppName(request));
configRequestInfo.setBetaIps(request.getHeader("betaIps"));
String encryptedDataKey = pair.getFirst();
return Result.success(configOperationService.publishConfig(configForm, configRequestInfo, encryptedDataKey));
}
/**
* Synchronously delete all pre-aggregation data under a dataId.
*
* @throws NacosApiException NacosApiException.
*/
@DeleteMapping
@Secured(action = ActionTypes.WRITE, signType = SignType.CONFIG)
public Result<Boolean> deleteConfig(HttpServletRequest request, @RequestParam("dataId") String dataId,
@RequestParam("group") String group,
@RequestParam(value = "namespaceId", required = false, defaultValue = StringUtils.EMPTY) String namespaceId,
@RequestParam(value = "tag", required = false) String tag) throws NacosException {
// check namespaceId
ParamUtils.checkTenantV2(namespaceId);
ParamUtils.checkParam(dataId, group, "datumId", "rm");
ParamUtils.checkParamV2(tag);
String clientIp = RequestUtil.getRemoteIp(request);
String srcUser = RequestUtil.getSrcUserName(request);
return Result.success(configOperationService.deleteConfig(dataId, group, namespaceId, tag, clientIp, srcUser));
}
}

View File

@ -0,0 +1,154 @@
/*
* 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.config.server.controller.v2;
import com.alibaba.nacos.api.annotation.NacosApi;
import com.alibaba.nacos.api.exception.api.NacosApiException;
import com.alibaba.nacos.api.model.v2.ErrorCode;
import com.alibaba.nacos.api.model.v2.Result;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.common.utils.NamespaceUtil;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.config.server.constant.Constants;
import com.alibaba.nacos.config.server.model.ConfigHistoryInfo;
import com.alibaba.nacos.config.server.model.ConfigInfoWrapper;
import com.alibaba.nacos.config.server.model.Page;
import com.alibaba.nacos.config.server.service.HistoryService;
import com.alibaba.nacos.config.server.utils.ParamUtils;
import com.alibaba.nacos.plugin.auth.constant.ActionTypes;
import com.alibaba.nacos.plugin.auth.constant.SignType;
import com.alibaba.nacos.plugin.auth.exception.AccessException;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* config history management controller [v2].
* @author dongyafei
* @date 2022/7/25
*/
@NacosApi
@RestController
@RequestMapping(Constants.HISTORY_CONTROLLER_V2_PATH)
public class HistoryControllerV2 {
private final HistoryService historyService;
public HistoryControllerV2(HistoryService historyService) {
this.historyService = historyService;
}
/**
* Query the list history config. notes:
*
* @param dataId dataId string value [required].
* @param group group string value [required].
* @param namespaceId namespaceId.
* @param pageNo pageNo integer value.
* @param pageSize pageSize integer value.
* @return the page of history config.
* @since 2.0.3 add {@link Secured} for history config permission check.
*/
@GetMapping("/list")
@Secured(action = ActionTypes.READ, signType = SignType.CONFIG)
public Result<Page<ConfigHistoryInfo>> listConfigHistory(
@RequestParam("dataId") String dataId,
@RequestParam("group") String group,
@RequestParam(value = "namespaceId", required = false, defaultValue = StringUtils.EMPTY) String namespaceId,
@RequestParam(value = "pageNo", required = false, defaultValue = "1") Integer pageNo,
@RequestParam(value = "pageSize", required = false, defaultValue = "100") Integer pageSize) {
pageSize = Math.min(500, pageSize);
return Result.success(historyService.listConfigHistory(dataId, group, namespaceId, pageNo, pageSize));
}
/**
* Query the detailed configuration history information. notes:
*
* @param nid history_config_info nid
* @param dataId dataId @since 2.0.3
* @param group groupId @since 2.0.3
* @param namespaceId namespaceId @since 2.0.3
* @return history config info
* @since 2.0.3 add {@link Secured}, dataId, groupId and tenant for history config permission check.
*/
@GetMapping
@Secured(action = ActionTypes.READ, signType = SignType.CONFIG)
public Result<ConfigHistoryInfo> getConfigHistoryInfo(
@RequestParam("dataId") String dataId,
@RequestParam("group") String group,
@RequestParam(value = "namespaceId", required = false, defaultValue = StringUtils.EMPTY) String namespaceId,
@RequestParam("nid") Long nid) throws AccessException, NacosApiException {
ConfigHistoryInfo configHistoryInfo;
try {
configHistoryInfo = historyService.getConfigHistoryInfo(dataId, group, namespaceId, nid);
} catch (DataAccessException e) {
throw new NacosApiException(HttpStatus.NOT_FOUND.value(), ErrorCode.RESOURCE_NOT_FOUND,
"certain config history for nid = " + nid + " not exist");
}
return Result.success(configHistoryInfo);
}
/**
* Query previous config history information. notes:
*
* @param id config_info id
* @param dataId dataId @since 2.0.3
* @param group groupId @since 2.0.3
* @param namespaceId namespaceId @since 2.0.3
* @return history config info
* @since 2.0.3 add {@link Secured}, dataId, groupId and tenant for history config permission check.
*/
@GetMapping(value = "/previous")
@Secured(action = ActionTypes.READ, signType = SignType.CONFIG)
public Result<ConfigHistoryInfo> getPreviousConfigHistoryInfo(
@RequestParam("dataId") String dataId,
@RequestParam("group") String group,
@RequestParam(value = "namespaceId", required = false, defaultValue = StringUtils.EMPTY) String namespaceId,
@RequestParam("id") Long id) throws AccessException, NacosApiException {
ConfigHistoryInfo configHistoryInfo;
try {
configHistoryInfo = historyService.getPreviousConfigHistoryInfo(dataId, group, namespaceId, id);
} catch (DataAccessException e) {
throw new NacosApiException(HttpStatus.NOT_FOUND.value(), ErrorCode.RESOURCE_NOT_FOUND,
"previous config history for id = " + id + " not exist");
}
return Result.success(configHistoryInfo);
}
/**
* Query configs list by namespace.
*
* @param namespaceId config_info namespace
* @return list
* @since 2.1.1
*/
@GetMapping(value = "/configs")
@Secured(action = ActionTypes.READ, signType = SignType.CONFIG)
public Result<List<ConfigInfoWrapper>> getConfigsByTenant(@RequestParam("namespaceId") String namespaceId)
throws NacosApiException {
// check namespaceId
ParamUtils.checkTenantV2(namespaceId);
namespaceId = NamespaceUtil.processNamespaceParameter(namespaceId);
return Result.success(historyService.getConfigListByNamespace(namespaceId));
}
}

View File

@ -19,6 +19,7 @@ package com.alibaba.nacos.config.server.exception;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.common.utils.ExceptionUtil;
import com.alibaba.nacos.config.server.monitor.MetricsMonitor;
import org.springframework.core.annotation.Order;
import org.springframework.dao.DataAccessException;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
@ -31,6 +32,7 @@ import java.io.IOException;
*
* @author Nacos
*/
@Order(0)
@ControllerAdvice
public class GlobalExceptionHandler {

View File

@ -25,7 +25,7 @@ import java.io.Serializable;
*/
public class ConfigAdvanceInfo implements Serializable {
static final long serialVersionUID = -1L;
static final long serialVersionUID = 3148031484920416869L;
private long createTime;

View File

@ -24,7 +24,7 @@ package com.alibaba.nacos.config.server.model;
*/
public class ConfigInfo extends ConfigInfoBase {
static final long serialVersionUID = -1L;
static final long serialVersionUID = 3115358782431229202L;
private String tenant;

View File

@ -32,7 +32,7 @@ import java.io.Serializable;
*/
public class ConfigInfoBase implements Serializable, Comparable<ConfigInfoBase> {
static final long serialVersionUID = -1L;
static final long serialVersionUID = 265316491795790798L;
@JsonSerialize(using = ToStringSerializer.class)
private long id;

View File

@ -24,7 +24,7 @@ package com.alibaba.nacos.config.server.model;
*/
public class ConfigInfoBaseEx extends ConfigInfoBase {
private static final long serialVersionUID = -1L;
private static final long serialVersionUID = 5802322506486922169L;
/**
* Single message status code, when querying for batch.

View File

@ -23,7 +23,7 @@ package com.alibaba.nacos.config.server.model;
*/
public class ConfigInfoEx extends ConfigInfo {
private static final long serialVersionUID = -1L;
private static final long serialVersionUID = 8905036592920606608L;
/**
* Single message status code, when querying for batch.

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