Merge branch 'develop' of https://github.com/alibaba/nacos into new_develop

This commit is contained in:
chuntaojun 2020-07-17 00:06:39 +08:00
commit abee9c4dcf
409 changed files with 18943 additions and 17128 deletions

View File

@ -22,7 +22,7 @@ Nacos provides four major functions.
* **Dynamic Configuration Management**
Dynamic Configuration Service allows you to manage configurations of all services in a centralized and dynamic manner across all environments. Nacos eliminates the need to redeploy applications and services when configurations are updatedwhich makes configuration changes more efficient and agile.
Dynamic Configuration Service allows you to manage configurations of all services in a centralized and dynamic manner across all environments. Nacos eliminates the need to redeploy applications and services when configurations are updated, which makes configuration changes more efficient and agile.
* **Dynamic DNS Service**

View File

@ -15,26 +15,26 @@
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>nacos-all</artifactId>
<groupId>com.alibaba.nacos</groupId>
<version>1.3.1-BETA</version>
<version>1.3.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>nacos-address</artifactId>
<packaging>jar</packaging>
<name>nacos-address ${project.version}</name>
<url>http://nacos.io</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
@ -62,7 +62,7 @@
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
@ -70,7 +70,7 @@
</resource>
</resources>
</build>
<reporting>
<plugins>
<plugin>
@ -79,7 +79,7 @@
</plugin>
</plugins>
</reporting>
<profiles>
<profile>
<id>release-address</id>

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.address;
import org.springframework.boot.SpringApplication;
@ -26,8 +27,9 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
*/
@SpringBootApplication(scanBasePackages = "com.alibaba.nacos")
public class AddressServer {
public static void main(String[] args) {
SpringApplication.run(AddressServer.class, args);
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.address.component;
import com.alibaba.nacos.address.constant.AddressServerConstants;
@ -34,32 +35,38 @@ import java.util.List;
*/
@Component
public class AddressServerGeneratorManager {
/**
* Generate product name.
*
* @param name name
* @return product
*/
public String generateProductName(String name) {
if (StringUtils.isBlank(name) || AddressServerConstants.DEFAULT_PRODUCT.equals(name)) {
return AddressServerConstants.ALIWARE_NACOS_DEFAULT_PRODUCT_NAME;
}
return String.format(AddressServerConstants.ALIWARE_NACOS_PRODUCT_DOM_TEMPLATE, name);
}
/**
* Note: if the parameter inputted is empty then will return the empty list.
*
* @param serviceName
* @param clusterName
* @param ipArray
* @return
* @param serviceName service name
* @param clusterName cluster name
* @param ipArray array of ips
* @return instance list
*/
public List<Instance> generateInstancesByIps(String serviceName, String rawProductName, String clusterName, String[] ipArray) {
if (StringUtils.isEmpty(serviceName)
|| StringUtils.isEmpty(clusterName)
|| ipArray == null || ipArray.length == 0) {
public List<Instance> generateInstancesByIps(String serviceName, String rawProductName, String clusterName,
String[] ipArray) {
if (StringUtils.isEmpty(serviceName) || StringUtils.isEmpty(clusterName) || ipArray == null
|| ipArray.length == 0) {
return Collections.emptyList();
}
List<Instance> instanceList = new ArrayList<>(ipArray.length);
for (String ip : ipArray) {
String[] ipAndPort = generateIpAndPort(ip);
@ -73,46 +80,50 @@ public class AddressServerGeneratorManager {
instance.setEphemeral(false);
instanceList.add(instance);
}
return instanceList;
}
public String[] generateIpAndPort(String ip) {
private String[] generateIpAndPort(String ip) {
int index = ip.indexOf(AddressServerConstants.IP_PORT_SEPARATOR);
if (index != -1) {
return new String[]{ip.substring(0, index), ip.substring(index + 1)};
return new String[] {ip.substring(0, index), ip.substring(index + 1)};
}
return new String[]{ip, String.valueOf(AddressServerConstants.DEFAULT_SERVER_PORT)};
return new String[] {ip, String.valueOf(AddressServerConstants.DEFAULT_SERVER_PORT)};
}
/**
* Generate response ips.
*
* @param instanceList a instance set will generate string response to client.
* @return the result of response to client
*/
public String generateResponseIps(List<Instance> instanceList) {
StringBuilder ips = new StringBuilder();
instanceList.forEach(instance -> {
ips.append(instance.getIp() + ":" + instance.getPort());
ips.append("\n");
});
return ips.toString();
}
/**
* @param rawServiceName the raw service name will not contains the {@Constans.DEFAULT_GROUP}
* Generate nacos service name.
*
* @param rawServiceName the raw service name will not contains the {@link Constants#DEFAULT_GROUP}.
* @return the nacos service name
*/
public String generateNacosServiceName(String rawServiceName) {
if (rawServiceName.indexOf(Constants.DEFAULT_GROUP) != -1) {
return rawServiceName;
}
return Constants.DEFAULT_GROUP + AddressServerConstants.GROUP_SERVICE_NAME_SEP + rawServiceName;
}
}

View File

@ -13,9 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.address.component;
import com.alibaba.nacos.address.constant.AddressServerConstants;
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
@ -28,51 +30,51 @@ import org.springframework.stereotype.Component;
*/
@Component
public class AddressServerManager {
public String getRawProductName(String name) {
if (StringUtils.isBlank(name) || AddressServerConstants.DEFAULT_PRODUCT.equals(name)) {
return AddressServerConstants.DEFAULT_PRODUCT;
}
return name;
}
/**
* <p>
* if the name is empty then return the default {@UtilAndCommons#DEFAULT_CLUSTER_NAME},
* <p>
* or return the source name by input
* If the name is empty then return the default {@link UtilsAndCommons#DEFAULT_CLUSTER_NAME}, or return the source
* name by input.
*
* @param name
* @return
* @param name name
* @return default cluster name
*/
public String getDefaultClusterNameIfEmpty(String name) {
if (StringUtils.isEmpty(name) || AddressServerConstants.DEFAULT_GET_CLUSTER.equals(name)) {
return AddressServerConstants.DEFAULT_GET_CLUSTER;
}
return name;
}
public String getRawClusterName(String name) {
return getDefaultClusterNameIfEmpty(name);
}
/**
* Split ips.
*
* @param ips multi ip will separator by the ','
* @return
* @return array of ip
*/
public String[] splitIps(String ips) {
if (StringUtils.isBlank(ips)) {
return new String[0];
}
return ips.split(AddressServerConstants.MULTI_IPS_SEPARATOR);
}
}

View File

@ -13,64 +13,65 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.address.constant;
import com.alibaba.nacos.naming.misc.UtilsAndCommons;
/**
* Uniform constant parameter naming for address servers and default values for related parameters
* Uniform constant parameter naming for address servers and default values for related parameters.
*
* @author pbting
* @date 2019-06-17 7:23 PM
* @since 1.1.0
*/
public interface AddressServerConstants {
/**
* the default server port when create the Instance object.
*/
int DEFAULT_SERVER_PORT = 8848;
/**
* when post ips is not given the product,then use the default.
*/
String DEFAULT_PRODUCT = "nacos";
/**
* the separator between ip and port.
*/
String IP_PORT_SEPARATOR = ":";
/**
* the separator for {@Service#name} between raw service name and group
* the separator for service name between raw service name and group.
*/
String GROUP_SERVICE_NAME_SEP = "@@";
/**
* when post ips is not given the cluster,then use the default.
*/
String DEFAULT_GET_CLUSTER = "serverlist";
/**
* post multi ip will use the "," to separator
* post multi ip will use the "," to separator.
*/
String MULTI_IPS_SEPARATOR = ",";
/**
* the default product name when deploy nacos with naming and config
* the default product name when deploy nacos with naming and config.
*/
String ALIWARE_NACOS_DEFAULT_PRODUCT_NAME = "nacos.as.default";
/**
* when the config and naming will separate deploy,then must specify product name by the client
* when the config and naming will separate deploy,then must specify product name by the client.
*/
String ALIWARE_NACOS_PRODUCT_DOM_TEMPLATE = "nacos.as.%s";
/**
* the url for address server prefix
* the url for address server prefix.
*/
String ADDRESS_SERVER_REQUEST_URL =
UtilsAndCommons.NACOS_SERVER_CONTEXT + UtilsAndCommons.NACOS_SERVER_VERSION + "/as";
UtilsAndCommons.NACOS_SERVER_CONTEXT + UtilsAndCommons.NACOS_SERVER_VERSION + "/as";
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.address.controller;
import com.alibaba.nacos.address.component.AddressServerGeneratorManager;
@ -38,46 +39,49 @@ import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* Address server cluster controller.
*
* @author pbting
* @date 2019-06-10 9:59 AM
* @since 1.1.0
*/
@RestController
@RequestMapping({AddressServerConstants.ADDRESS_SERVER_REQUEST_URL + "/nodes"})
public class AddressServerClusterController {
@Autowired
private ServiceManager serviceManager;
@Autowired
private AddressServerManager addressServerManager;
@Autowired
private AddressServerGeneratorManager addressServerGeneratorManager;
/**
* Create new cluster.
*
* @param product Ip list of products to be associated
* @param cluster Ip list of product cluster to be associated
* @param ips will post ip list.
* @return
* @return result of create new cluster
*/
@RequestMapping(value = "", method = RequestMethod.POST)
public ResponseEntity postCluster(@RequestParam(required = false) String product,
@RequestParam(required = false) String cluster,
@RequestParam(name = "ips") String ips) {
@RequestParam(required = false) String cluster, @RequestParam(name = "ips") String ips) {
//1. prepare the storage name for product and cluster
String productName = addressServerGeneratorManager.generateProductName(product);
String clusterName = addressServerManager.getDefaultClusterNameIfEmpty(cluster);
//2. prepare the response name for product and cluster to client
String rawProductName = addressServerManager.getRawProductName(product);
String rawClusterName = addressServerManager.getRawClusterName(cluster);
Loggers.addressLogger.info("put cluster node,the cluster name is " + cluster + "; the product name=" + product + "; the ip list=" + ips);
Loggers.ADDRESS_LOGGER.info("put cluster node,the cluster name is " + cluster + "; the product name=" + product
+ "; the ip list=" + ips);
ResponseEntity responseEntity;
try {
String serviceName = addressServerGeneratorManager.generateNacosServiceName(productName);
Cluster clusterObj = new Cluster();
clusterObj.setName(clusterName);
clusterObj.setHealthChecker(new AbstractHealthChecker.None());
@ -85,48 +89,54 @@ public class AddressServerClusterController {
String[] ipArray = addressServerManager.splitIps(ips);
String checkResult = AddressServerParamCheckUtil.checkIps(ipArray);
if (AddressServerParamCheckUtil.CHECK_OK.equals(checkResult)) {
List<Instance> instanceList = addressServerGeneratorManager.generateInstancesByIps(serviceName, rawProductName, clusterName, ipArray);
List<Instance> instanceList = addressServerGeneratorManager
.generateInstancesByIps(serviceName, rawProductName, clusterName, ipArray);
for (Instance instance : instanceList) {
serviceManager.registerInstance(Constants.DEFAULT_NAMESPACE_ID, serviceName, instance);
}
responseEntity = ResponseEntity.ok("product=" + rawProductName + ",cluster=" + rawClusterName + "; put success with size=" + instanceList.size());
responseEntity = ResponseEntity
.ok("product=" + rawProductName + ",cluster=" + rawClusterName + "; put success with size="
+ instanceList.size());
} else {
responseEntity = ResponseEntity.status(HttpStatus.BAD_REQUEST).body(checkResult);
}
} catch (Exception e) {
responseEntity = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
}
return responseEntity;
}
/**
* Delete cluster.
*
* @param product Ip list of products to be associated
* @param cluster Ip list of product cluster to be associated
* @param ips will delete ips.
* @return
* @return delete result
*/
@RequestMapping(value = "", method = RequestMethod.DELETE)
public ResponseEntity deleteCluster(@RequestParam(required = false) String product,
@RequestParam(required = false) String cluster,
@RequestParam String ips) {
@RequestParam(required = false) String cluster, @RequestParam String ips) {
//1. prepare the storage name for product and cluster
String productName = addressServerGeneratorManager.generateProductName(product);
String clusterName = addressServerManager.getDefaultClusterNameIfEmpty(cluster);
//2. prepare the response name for product and cluster to client
String rawProductName = addressServerManager.getRawProductName(product);
String rawClusterName = addressServerManager.getRawClusterName(cluster);
ResponseEntity responseEntity = ResponseEntity.status(HttpStatus.OK).body("product=" + rawProductName + ", cluster=" + rawClusterName + " delete success.");
ResponseEntity responseEntity = ResponseEntity.status(HttpStatus.OK)
.body("product=" + rawProductName + ", cluster=" + rawClusterName + " delete success.");
try {
String serviceName = addressServerGeneratorManager.generateNacosServiceName(productName);
Service service = serviceManager.getService(Constants.DEFAULT_NAMESPACE_ID, serviceName);
if (service == null) {
responseEntity = ResponseEntity.status(HttpStatus.NOT_FOUND).body("product=" + rawProductName + " not found.");
responseEntity = ResponseEntity.status(HttpStatus.NOT_FOUND)
.body("product=" + rawProductName + " not found.");
} else {
if (StringUtils.isBlank(ips)) {
// delete all ips from the cluster
responseEntity = ResponseEntity.status(HttpStatus.BAD_REQUEST).body("ips must not be empty.");
@ -135,19 +145,21 @@ public class AddressServerClusterController {
String[] ipArray = addressServerManager.splitIps(ips);
String checkResult = AddressServerParamCheckUtil.checkIps(ipArray);
if (AddressServerParamCheckUtil.CHECK_OK.equals(checkResult)) {
List<Instance> instanceList = addressServerGeneratorManager.generateInstancesByIps(serviceName, rawProductName, clusterName, ipArray);
serviceManager.removeInstance(Constants.DEFAULT_NAMESPACE_ID, serviceName, false, instanceList.toArray(new Instance[instanceList.size()]));
List<Instance> instanceList = addressServerGeneratorManager
.generateInstancesByIps(serviceName, rawProductName, clusterName, ipArray);
serviceManager.removeInstance(Constants.DEFAULT_NAMESPACE_ID, serviceName, false,
instanceList.toArray(new Instance[instanceList.size()]));
} else {
responseEntity = ResponseEntity.status(HttpStatus.BAD_REQUEST).body(checkResult);
}
}
}
} catch (Exception e) {
responseEntity = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getCause());
}
return responseEntity;
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.address.controller;
import com.alibaba.nacos.address.component.AddressServerGeneratorManager;
@ -29,42 +30,46 @@ import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* Server list controller.
*
* @author pbting
* @date 2019-06-18 5:04 PM
* @since 1.1.0
*/
@RestController
public class ServerListController {
@Autowired
private ServiceManager serviceManager;
@Autowired
private AddressServerGeneratorManager addressServerBuilderManager;
/**
* Get cluster.
*
* @param product will get Ip list of that products to be associated
* @param cluster will get Ip list of that product cluster to be associated
* @return
* @return result of get
*/
@RequestMapping(value = "/{product}/{cluster}", method = RequestMethod.GET)
public ResponseEntity getCluster(@PathVariable String product,
@PathVariable String cluster) {
public ResponseEntity getCluster(@PathVariable String product, @PathVariable String cluster) {
String productName = addressServerBuilderManager.generateProductName(product);
String serviceName = addressServerBuilderManager.generateNacosServiceName(productName);
Service service = serviceManager.getService(Constants.DEFAULT_NAMESPACE_ID, serviceName);
if (service == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("product=" + product + " not found.");
}
if (!service.getClusterMap().containsKey(cluster)) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("product=" + product + ",cluster=" + cluster + " not found.");
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body("product=" + product + ",cluster=" + cluster + " not found.");
}
Cluster clusterObj = service.getClusterMap().get(cluster);
return ResponseEntity.status(HttpStatus.OK).body(addressServerBuilderManager.generateResponseIps(clusterObj.allIPs(false)));
return ResponseEntity.status(HttpStatus.OK)
.body(addressServerBuilderManager.generateResponseIps(clusterObj.allIPs(false)));
}
}

View File

@ -13,16 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.address.misc;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Loggers holder.
*
* @author pbting
* @date 2019-07-04 4:34 PM
*/
public class Loggers {
public static final Logger addressLogger = LoggerFactory.getLogger("com.alibaba.nacos.address.main");
public static final Logger ADDRESS_LOGGER = LoggerFactory.getLogger("com.alibaba.nacos.address.main");
}

View File

@ -13,32 +13,39 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.address.util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Provides a unified tool class for address server parameter verification
* Provides a unified tool class for address server parameter verification.
*
* @author pbting
* @date 2019-06-19 11:19 AM
* @since 1.1.0
*/
public class AddressServerParamCheckUtil {
public static final String CHECK_OK = "ok";
public static final String ILLEGAL_IP_PREFIX = "illegal ip: ";
private static final String IP_REGEX = "(2(5[0-5]{1}|[0-4]\\d{1})|[0-1]?\\d{1,2})(\\.(2(5[0-5]{1}|[0-4]\\d{1})|[0-1]?\\d{1,2})){3}";
private static final Pattern IP_PATTERN = Pattern.compile(IP_REGEX);
/**
* Check ips.
*
* @param ips ips
* @return 'ok' if check passed, otherwise illegal ip
*/
public static String checkIps(String... ips) {
if (ips == null || ips.length == 0) {
return CHECK_OK;
}
// illegal response
@ -50,11 +57,11 @@ public class AddressServerParamCheckUtil {
}
illegalResponse.append(ip + ",");
}
if (illegalResponse.length() == 0) {
return CHECK_OK;
}
return ILLEGAL_IP_PREFIX + illegalResponse.substring(0, illegalResponse.length() - 1);
}
}

View File

@ -16,12 +16,12 @@
-->
<included>
<springProperty scope="context" name="logPath" source="nacos.logs.path" defaultValue="${user.home}/nacos/logs"/>
<property name="LOG_HOME" value="${logPath}"/>
<appender name="nacos-address"
class="ch.qos.logback.core.rolling.RollingFileAppender">
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/nacos-address.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
@ -36,7 +36,7 @@
<charset>UTF-8</charset>
</encoder>
</appender>
<logger name="com.alibaba.nacos.address.main" additivity="false">
<level value="INFO"/>
<appender-ref ref="nacos-address"/>

View File

@ -13,6 +13,5 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
server.port=8080
server.servlet.context-path=/

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.address;
import org.junit.Ignore;
@ -20,43 +21,39 @@ import org.junit.Test;
import java.util.HashMap;
/**
* @author pbting
* @date 2019-06-18 2:37 PM
*/
@Ignore
public class AddressServerControllerTests {
private static final String PRODUCT_NACOS = "nacos";
private static final String PRODUCT_CONFIG = "config";
private static final String PRODUCT_NAMING = "naming";
private static final String DEFAULT_URL_CLUSTER = "serverlist";
private static final String GET_SERVERLIST_URL_FORMART = "http://127.0.0.1:8080/%s/%s";
//-----------------product=nacos,cluster=DEFAULT -------------------//
/**
* test the default product and cluster
*/
@Test
public void postCluster() {
String ips = "127.0.0.100,127.0.0.102,127.0.0.104";
HashMap<String, String> params = new HashMap<>();
params.put("ips", ips);
String response = SimpleHttpTestUtils.doPost("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
System.err.println(response);
}
@Test
public void getCluster() {
String getUrl = String.format(GET_SERVERLIST_URL_FORMART, PRODUCT_NACOS, DEFAULT_URL_CLUSTER);
String response = SimpleHttpTestUtils.doGet(getUrl, new HashMap<>(), "UTF-8");
System.err.println(response);
}
@Test
public void deleteCluster() {
HashMap<String, String> deleteIp = new HashMap<>();
@ -64,7 +61,7 @@ public class AddressServerControllerTests {
String response = SimpleHttpTestUtils.doDelete("http://127.0.0.1:8080/nacos/v1/as/nodes", deleteIp, "UTF-8");
System.err.println(response);
}
@Test
public void deleteClusterWithSpecIp() {
HashMap<String, String> params = new HashMap<>();
@ -72,26 +69,22 @@ public class AddressServerControllerTests {
String response = SimpleHttpTestUtils.doDelete("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
System.err.println(response);
}
@Test
public void putCluster() {
String ips = "127.0.0.114";
HashMap<String, String> params = new HashMap<>();
params.put("ips", ips);
String response = SimpleHttpTestUtils.doPut("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
System.err.println(response);
}
//-----------------product=config,cluster=cluster01 -------------------//
/**
* test with product
*/
@Test
public void postClusterWithProduct() {
String ips = "127.0.0.101,127.0.0.102,127.0.0.103";
HashMap<String, String> params = new HashMap<>();
params.put("ips", ips);
@ -99,7 +92,7 @@ public class AddressServerControllerTests {
String response = SimpleHttpTestUtils.doPost("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
System.err.println(response);
}
@Test
public void getClusterWithProduct() {
HashMap<String, String> params = new HashMap<>();
@ -107,7 +100,7 @@ public class AddressServerControllerTests {
String response = SimpleHttpTestUtils.doGet(getUrl, params, "UTF-8");
System.err.println(response);
}
@Test
public void deleteClusterWithProduct() {
HashMap<String, String> params = new HashMap<>();
@ -115,7 +108,7 @@ public class AddressServerControllerTests {
String response = SimpleHttpTestUtils.doDelete("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
System.err.println(response);
}
@Test
public void deleteClusterWithProductAndIp() {
HashMap<String, String> params = new HashMap<>();
@ -124,10 +117,10 @@ public class AddressServerControllerTests {
String response = SimpleHttpTestUtils.doDelete("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
System.err.println(response);
}
@Test
public void putClusterWithProduct() {
String ips = "127.0.0.196";
HashMap<String, String> params = new HashMap<>();
params.put("ips", ips);
@ -135,16 +128,12 @@ public class AddressServerControllerTests {
String response = SimpleHttpTestUtils.doPut("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
System.err.println(response);
}
//-----------------product=naming,cluster=cluster01 -------------------//
/**
* test with product and cluster
*/
@Test
public void postClusterWithProductAndCluster() {
String ips = "127.0.0.100,127.0.0.200,127.0.0.31";
HashMap<String, String> params = new HashMap<>();
params.put("ips", ips);
@ -153,7 +142,7 @@ public class AddressServerControllerTests {
String response = SimpleHttpTestUtils.doPost("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
System.err.println(response);
}
@Test
public void getClusterWithProductAndCluster() {
HashMap<String, String> params = new HashMap<>();
@ -161,7 +150,7 @@ public class AddressServerControllerTests {
String response = SimpleHttpTestUtils.doGet(getUrl, params, "UTF-8");
System.err.println(response);
}
@Test
public void deleteClusterWithProductAndCluster() {
HashMap<String, String> params = new HashMap<>();
@ -170,7 +159,7 @@ public class AddressServerControllerTests {
String response = SimpleHttpTestUtils.doDelete("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
System.err.println(response);
}
@Test
public void deleteClusterWithProductAndClusterAndIp() {
HashMap<String, String> params = new HashMap<>();
@ -180,10 +169,10 @@ public class AddressServerControllerTests {
String response = SimpleHttpTestUtils.doDelete("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
System.err.println(response);
}
@Test
public void putClusterWithProductAndCluster() {
String ips = "127.0.0.171";
HashMap<String, String> params = new HashMap<>();
params.put("ips", ips);

View File

@ -13,22 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.address;
import com.alibaba.nacos.address.util.AddressServerParamCheckUtil;
import org.junit.Test;
/**
* @author pbting
* @date 2019-06-19 11:31 AM
*/
public class ParamCheckUtilTests {
@Test
public void checkIps() {
String[] ips = {"127.0.0.1"};
System.out.println(AddressServerParamCheckUtil.checkIps(ips));
String[] illlegalIps = {"127.100.19", "127.0.0.1"};
System.err.println(AddressServerParamCheckUtil.checkIps(illlegalIps));
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.address;
import com.alibaba.nacos.common.utils.IoUtils;
@ -26,49 +27,46 @@ import java.net.URL;
import java.net.URLEncoder;
import java.util.Map;
/**
* @author pbting
* @date 2019-06-18 2:40 PM
*/
public class SimpleHttpTestUtils {
private static final String REQUEST_METHOD_DELETE = "DELETE";
private static final String REQUEST_METHOD_PUT = "PUT";
private static final String REQUEST_METHOD_POST = "POST";
private static final String REQUEST_METHOD_GET = "GET";
/**
* 连接超时
* 连接超时.
*/
private static int CONNECT_TIME_OUT = 2000;
private static final int CONNECT_TIME_OUT = 2000;
/**
* 读取数据超时
* 读取数据超时.
*/
private static int READ_TIME_OUT = 2000;
private static final int READ_TIME_OUT = 2000;
/**
* 请求编码
* 请求编码.
*/
public static String REQUEST_ENCODING = "UTF-8";
public static final String REQUEST_ENCODING = "UTF-8";
/**
* 接收编码
* 接收编码.
*/
public static String RESPONSE_ENCODING = "UTF-8";
public static final String RESPONSE_ENCODING = "UTF-8";
public static final short OK = 200;
public static final short Bad_Request = 400;
public static final short Internal_Server_Error = 500;
public static final short BAD_REQUEST = 400;
public static final short INTERNAL_SERVER_ERROR = 500;
public static final short PARAM_ERROR_NO_ANALYSESOR = 1000;
/**
* <pre>
* 发送带参数的GET的HTTP请求
* </pre>
* 发送带参数的GET的HTTP请求.
*
* @param reqUrl HTTP请求URL
* @param paramMap 参数映射表
@ -77,11 +75,9 @@ public class SimpleHttpTestUtils {
public static String doGet(String reqUrl, Map<String, String> paramMap, String recvEncoding) {
return doRequest(reqUrl, paramMap, REQUEST_METHOD_GET, recvEncoding);
}
/**
* <pre>
* 发送带参数的POST的HTTP请求
* </pre>
* 发送带参数的POST的HTTP请求.
*
* @param reqUrl HTTP请求URL
* @param paramMap 参数映射表
@ -90,11 +86,9 @@ public class SimpleHttpTestUtils {
public static String doPost(String reqUrl, Map<String, String> paramMap, String recvEncoding) {
return doRequest(reqUrl, paramMap, REQUEST_METHOD_POST, recvEncoding);
}
/**
* <pre>
* 发送带参数的 PUT HTTP 请求
* </pre>
* 发送带参数的 PUT HTTP 请求.
*
* @param reqUrl HTTP请求URL
* @param paramMap 参数映射表
@ -103,11 +97,9 @@ public class SimpleHttpTestUtils {
public static String doPut(String reqUrl, Map<String, String> paramMap, String recvEncoding) {
return doRequest(reqUrl, paramMap, REQUEST_METHOD_PUT, recvEncoding);
}
/**
* <pre>
* 发送带参数的 DELETE HTTP 请求
* </pre>
* 发送带参数的 DELETE HTTP 请求.
*
* @param reqUrl HTTP请求URL
* @param paramMap 参数映射表
@ -116,13 +108,15 @@ public class SimpleHttpTestUtils {
public static String doDelete(String reqUrl, Map<String, String> paramMap, String recvEncoding) {
return doRequest(reqUrl, paramMap, REQUEST_METHOD_DELETE, recvEncoding);
}
private static String doRequest(String reqUrl, Map<String, String> paramMap, String reqMethod, String recvEncoding) {
private static String doRequest(String reqUrl, Map<String, String> paramMap, String reqMethod,
String recvEncoding) {
return doExecute(reqUrl, paramMap, reqMethod, recvEncoding);
}
private static String doExecute(String reqUrl, Map<String, String> paramMap, String reqMethod, String recvEncoding) {
private static String doExecute(String reqUrl, Map<String, String> paramMap, String reqMethod,
String recvEncoding) {
HttpURLConnection urlCon = null;
String responseContent = null;
try {
@ -134,13 +128,13 @@ public class SimpleHttpTestUtils {
params.append(URLEncoder.encode(element.getValue(), REQUEST_ENCODING));
params.append("&");
}
if (params.length() > 0) {
params = params.deleteCharAt(params.length() - 1);
}
if (params.length() > 0 &&
(REQUEST_METHOD_GET.equals(reqMethod) || REQUEST_METHOD_DELETE.equals(reqMethod))) {
if (params.length() > 0 && (REQUEST_METHOD_GET.equals(reqMethod) || REQUEST_METHOD_DELETE
.equals(reqMethod))) {
reqUrl = reqUrl + "?" + params.toString();
}
}
@ -169,7 +163,7 @@ public class SimpleHttpTestUtils {
responseContent = tempStr.toString();
rd.close();
in.close();
urlCon.getResponseMessage();
} catch (IOException e) {
e.printStackTrace();
@ -178,5 +172,5 @@ public class SimpleHttpTestUtils {
}
return responseContent;
}
}

View File

@ -19,7 +19,7 @@
<parent>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-all</artifactId>
<version>1.3.1-BETA</version>
<version>1.3.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -154,4 +154,10 @@ public class NacosException extends Exception {
public static final int OVER_THRESHOLD = 503;
public static final int RESOURCE_NOT_FOUND = -404;
/**
* http client error code,
* ome exceptions that occurred when the use the Nacos RestTemplate and Nacos AsyncRestTemplate.
*/
public static final int HTTP_CLIENT_ERROR_CODE = -500;
}

View File

@ -16,6 +16,8 @@
package com.alibaba.nacos.api.naming.pojo.healthcheck;
import com.alibaba.nacos.api.exception.runtime.NacosDeserializationException;
import com.alibaba.nacos.api.exception.runtime.NacosSerializationException;
import com.alibaba.nacos.api.naming.pojo.healthcheck.AbstractHealthChecker.None;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
@ -76,8 +78,7 @@ public class HealthCheckerFactory {
try {
return MAPPER.readValue(jsonString, AbstractHealthChecker.class);
} catch (IOException e) {
// TODO replace with NacosDeserializeException.
throw new RuntimeException("Deserialize health checker from json failed", e);
throw new NacosDeserializationException(AbstractHealthChecker.class, e);
}
}
@ -91,8 +92,7 @@ public class HealthCheckerFactory {
try {
return MAPPER.writeValueAsString(healthChecker);
} catch (JsonProcessingException e) {
// TODO replace with NacosSerializeException.
throw new RuntimeException("Serialize health checker to json failed", e);
throw new NacosSerializationException(healthChecker.getClass(), e);
}
}
}

View File

@ -15,100 +15,106 @@
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-all</artifactId>
<version>1.3.1-BETA</version>
<version>1.3.1</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>nacos-client</artifactId>
<packaging>jar</packaging>
<name>nacos-client ${project.version}</name>
<url>http://nacos.io</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>nacos-common</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>nacos-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<artifactId>commons-codec</artifactId>
<groupId>commons-codec</groupId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>net.jcip</groupId>
<artifactId>jcip-annotations</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient</artifactId>
@ -122,17 +128,17 @@
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>7</source>
<target>7</target>
<source>6</source>
<target>6</target>
</configuration>
</plugin>
</plugins>

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config;
import com.alibaba.nacos.api.PropertyKeyConst;
@ -45,29 +46,33 @@ import java.util.List;
import java.util.Properties;
/**
* Config Impl
* Config Impl.
*
* @author Nacos
*/
@SuppressWarnings("PMD.ServiceOrDaoClassShouldEndWithImplRule")
public class NacosConfigService implements ConfigService {
private static final Logger LOGGER = LogUtils.logger(NacosConfigService.class);
private static final long POST_TIMEOUT = 3000L;
/**
* http agent
* http agent.
*/
private HttpAgent agent;
private final HttpAgent agent;
/**
* longpolling
* long polling.
*/
private ClientWorker worker;
private final ClientWorker worker;
private String namespace;
private String encode;
private ConfigFilterChainManager configFilterChainManager = new ConfigFilterChainManager();
private final String encode;
private final ConfigFilterChainManager configFilterChainManager = new ConfigFilterChainManager();
public NacosConfigService(Properties properties) throws NacosException {
ValidatorUtils.checkInitParam(properties);
String encodeTmp = properties.getProperty(PropertyKeyConst.ENCODE);
@ -77,98 +82,99 @@ public class NacosConfigService implements ConfigService {
this.encode = encodeTmp.trim();
}
initNamespace(properties);
this.agent = new MetricsHttpAgent(new ServerHttpAgent(properties));
this.agent.start();
this.worker = new ClientWorker(this.agent, this.configFilterChainManager, properties);
}
private void initNamespace(Properties properties) {
namespace = ParamUtil.parseNamespace(properties);
properties.put(PropertyKeyConst.NAMESPACE, namespace);
}
@Override
public String getConfig(String dataId, String group, long timeoutMs) throws NacosException {
return getConfigInner(namespace, dataId, group, timeoutMs);
}
@Override
public String getConfigAndSignListener(String dataId, String group, long timeoutMs, Listener listener) throws NacosException {
public String getConfigAndSignListener(String dataId, String group, long timeoutMs, Listener listener)
throws NacosException {
String content = getConfig(dataId, group, timeoutMs);
worker.addTenantListenersWithContent(dataId, group, content, Arrays.asList(listener));
return content;
}
@Override
public void addListener(String dataId, String group, Listener listener) throws NacosException {
worker.addTenantListeners(dataId, group, Arrays.asList(listener));
}
@Override
public boolean publishConfig(String dataId, String group, String content) throws NacosException {
return publishConfigInner(namespace, dataId, group, null, null, null, content);
}
@Override
public boolean removeConfig(String dataId, String group) throws NacosException {
return removeConfigInner(namespace, dataId, group, null);
}
@Override
public void removeListener(String dataId, String group, Listener listener) {
worker.removeTenantListener(dataId, group, listener);
}
private String getConfigInner(String tenant, String dataId, String group, long timeoutMs) throws NacosException {
group = null2defaultGroup(group);
ParamUtils.checkKeyParam(dataId, group);
ConfigResponse cr = new ConfigResponse();
cr.setDataId(dataId);
cr.setTenant(tenant);
cr.setGroup(group);
// 优先使用本地配置
String content = LocalConfigInfoProcessor.getFailover(agent.getName(), dataId, group, tenant);
if (content != null) {
LOGGER.warn("[{}] [get-config] get failover ok, dataId={}, group={}, tenant={}, config={}", agent.getName(),
dataId, group, tenant, ContentUtils.truncateContent(content));
dataId, group, tenant, ContentUtils.truncateContent(content));
cr.setContent(content);
configFilterChainManager.doFilter(null, cr);
content = cr.getContent();
return content;
}
try {
String[] ct = worker.getServerConfig(dataId, group, tenant, timeoutMs);
cr.setContent(ct[0]);
configFilterChainManager.doFilter(null, cr);
content = cr.getContent();
return content;
} catch (NacosException ioe) {
if (NacosException.NO_RIGHT == ioe.getErrCode()) {
throw ioe;
}
LOGGER.warn("[{}] [get-config] get from server error, dataId={}, group={}, tenant={}, msg={}",
agent.getName(), dataId, group, tenant, ioe.toString());
agent.getName(), dataId, group, tenant, ioe.toString());
}
LOGGER.warn("[{}] [get-config] get snapshot ok, dataId={}, group={}, tenant={}, config={}", agent.getName(),
dataId, group, tenant, ContentUtils.truncateContent(content));
dataId, group, tenant, ContentUtils.truncateContent(content));
content = LocalConfigInfoProcessor.getSnapshot(agent.getName(), dataId, group, tenant);
cr.setContent(content);
configFilterChainManager.doFilter(null, cr);
content = cr.getContent();
return content;
}
private String null2defaultGroup(String group) {
return (null == group) ? Constants.DEFAULT_GROUP : group.trim();
}
private boolean removeConfigInner(String tenant, String dataId, String group, String tag) throws NacosException {
group = null2defaultGroup(group);
ParamUtils.checkKeyParam(dataId, group);
@ -193,26 +199,26 @@ public class NacosConfigService implements ConfigService {
LOGGER.warn("[remove] error, " + dataId + ", " + group + ", " + tenant + ", msg: " + ioe.toString());
return false;
}
if (HttpURLConnection.HTTP_OK == result.code) {
LOGGER.info("[{}] [remove] ok, dataId={}, group={}, tenant={}", agent.getName(), dataId, group, tenant);
return true;
} else if (HttpURLConnection.HTTP_FORBIDDEN == result.code) {
LOGGER.warn("[{}] [remove] error, dataId={}, group={}, tenant={}, code={}, msg={}", agent.getName(), dataId,
group, tenant, result.code, result.content);
group, tenant, result.code, result.content);
throw new NacosException(result.code, result.content);
} else {
LOGGER.warn("[{}] [remove] error, dataId={}, group={}, tenant={}, code={}, msg={}", agent.getName(), dataId,
group, tenant, result.code, result.content);
group, tenant, result.code, result.content);
return false;
}
}
private boolean publishConfigInner(String tenant, String dataId, String group, String tag, String appName,
String betaIps, String content) throws NacosException {
String betaIps, String content) throws NacosException {
group = null2defaultGroup(group);
ParamUtils.checkParam(dataId, group, content);
ConfigRequest cr = new ConfigRequest();
cr.setDataId(dataId);
cr.setTenant(tenant);
@ -220,7 +226,7 @@ public class NacosConfigService implements ConfigService {
cr.setContent(content);
configFilterChainManager.doFilter(cr, null);
content = cr.getContent();
String url = Constants.CONFIG_CONTROLLER_PATH;
List<String> params = new ArrayList<String>();
params.add("dataId");
@ -241,38 +247,38 @@ public class NacosConfigService implements ConfigService {
params.add("tag");
params.add(tag);
}
List<String> headers = new ArrayList<String>();
if (StringUtils.isNotEmpty(betaIps)) {
headers.add("betaIps");
headers.add(betaIps);
}
HttpResult result = null;
try {
result = agent.httpPost(url, headers, params, encode, POST_TIMEOUT);
} catch (IOException ioe) {
LOGGER.warn("[{}] [publish-single] exception, dataId={}, group={}, msg={}", agent.getName(), dataId,
group, ioe.toString());
LOGGER.warn("[{}] [publish-single] exception, dataId={}, group={}, msg={}", agent.getName(), dataId, group,
ioe.toString());
return false;
}
if (HttpURLConnection.HTTP_OK == result.code) {
LOGGER.info("[{}] [publish-single] ok, dataId={}, group={}, tenant={}, config={}", agent.getName(), dataId,
group, tenant, ContentUtils.truncateContent(content));
group, tenant, ContentUtils.truncateContent(content));
return true;
} else if (HttpURLConnection.HTTP_FORBIDDEN == result.code) {
LOGGER.warn("[{}] [publish-single] error, dataId={}, group={}, tenant={}, code={}, msg={}", agent.getName(),
dataId, group, tenant, result.code, result.content);
dataId, group, tenant, result.code, result.content);
throw new NacosException(result.code, result.content);
} else {
LOGGER.warn("[{}] [publish-single] error, dataId={}, group={}, tenant={}, code={}, msg={}", agent.getName(),
dataId, group, tenant, result.code, result.content);
dataId, group, tenant, result.code, result.content);
return false;
}
}
@Override
public String getServerStatus() {
if (worker.isHealthServer()) {
@ -281,9 +287,9 @@ public class NacosConfigService implements ConfigService {
return "DOWN";
}
}
@Override
public void shutDown() throws NacosException{
public void shutDown() throws NacosException {
agent.shutdown();
worker.shutdown();
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.common;
import com.alibaba.nacos.common.utils.StringUtils;
@ -23,19 +24,19 @@ import com.alibaba.nacos.common.utils.StringUtils;
* @author Nacos
*/
public class GroupKey {
public static String getKey(String dataId, String group) {
return doGetKey(dataId, group, "");
return getKey(dataId, group, "");
}
public static String getKeyTenant(String dataId, String group, String tenant) {
return doGetKey(dataId, group, tenant);
}
public static String getKey(String dataId, String group, String datumStr) {
return doGetKey(dataId, group, datumStr);
}
public static String getKeyTenant(String dataId, String group, String tenant) {
return doGetKey(dataId, group, tenant);
}
private static String doGetKey(String dataId, String group, String datumStr) {
StringBuilder sb = new StringBuilder();
urlEncode(dataId, sb);
@ -45,16 +46,22 @@ public class GroupKey {
sb.append('+');
urlEncode(datumStr, sb);
}
return sb.toString();
}
static public String[] parseKey(String groupKey) {
/**
* Parse key.
*
* @param groupKey group key
* @return parsed key
*/
public static String[] parseKey(String groupKey) {
StringBuilder sb = new StringBuilder();
String dataId = null;
String group = null;
String tenant = null;
for (int i = 0; i < groupKey.length(); ++i) {
char c = groupKey.charAt(i);
if ('+' == c) {
@ -81,7 +88,7 @@ public class GroupKey {
sb.append(c);
}
}
if (StringUtils.isBlank(group)) {
group = sb.toString();
if (group.length() == 0) {
@ -93,12 +100,12 @@ public class GroupKey {
throw new IllegalArgumentException("invalid groupkey:" + groupKey);
}
}
return new String[] {dataId, group, tenant};
}
/**
* + -> %2B % -> %25
* + -> %2B % -> %25.
*/
static void urlEncode(String str, StringBuilder sb) {
for (int idx = 0; idx < str.length(); ++idx) {
@ -112,5 +119,5 @@ public class GroupKey {
}
}
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.filter.impl;
import com.alibaba.nacos.api.config.filter.IConfigContext;
@ -21,22 +22,22 @@ import java.util.HashMap;
import java.util.Map;
/**
* Config Context
* Config Context.
*
* @author Nacos
*/
public class ConfigContext implements IConfigContext {
private Map<String, Object> param = new HashMap<String, Object>();
private final Map<String, Object> param = new HashMap<String, Object>();
@Override
public Object getParameter(String key) {
return param.get(key);
}
@Override
public void setParameter(String key, Object value) {
param.put(key, value);
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.filter.impl;
import com.alibaba.nacos.api.config.filter.IConfigFilter;
@ -25,14 +26,20 @@ import com.google.common.collect.Lists;
import java.util.List;
/**
* Config Filter Chain Management
* Config Filter Chain Management.
*
* @author Nacos
*/
public class ConfigFilterChainManager implements IConfigFilterChain {
private List<IConfigFilter> filters = Lists.newArrayList();
private final List<IConfigFilter> filters = Lists.newArrayList();
/**
* Add filter.
*
* @param filter filter
* @return this
*/
public synchronized ConfigFilterChainManager addFilter(IConfigFilter filter) {
// 根据order大小顺序插入
int i = 0;
@ -48,28 +55,28 @@ public class ConfigFilterChainManager implements IConfigFilterChain {
break;
}
}
if (i == this.filters.size()) {
this.filters.add(i, filter);
}
return this;
}
@Override
public void doFilter(IConfigRequest request, IConfigResponse response) throws NacosException {
new VirtualFilterChain(this.filters).doFilter(request, response);
}
private static class VirtualFilterChain implements IConfigFilterChain {
private final List<? extends IConfigFilter> additionalFilters;
private int currentPosition = 0;
public VirtualFilterChain(List<? extends IConfigFilter> additionalFilters) {
this.additionalFilters = additionalFilters;
}
@Override
public void doFilter(final IConfigRequest request, final IConfigResponse response) throws NacosException {
if (this.currentPosition != this.additionalFilters.size()) {
@ -79,5 +86,5 @@ public class ConfigFilterChainManager implements IConfigFilterChain {
}
}
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.filter.impl;
import com.alibaba.nacos.api.config.filter.IConfigContext;
@ -22,56 +23,56 @@ import java.util.HashMap;
import java.util.Map;
/**
* Config Request
* Config Request.
*
* @author Nacos
*/
public class ConfigRequest implements IConfigRequest {
private Map<String, Object> param = new HashMap<String, Object>();
private IConfigContext configContext = new ConfigContext();
private final Map<String, Object> param = new HashMap<String, Object>();
private final IConfigContext configContext = new ConfigContext();
public String getTenant() {
return (String)param.get("tenant");
return (String) param.get("tenant");
}
public void setTenant(String tenant) {
param.put("tenant", tenant);
}
public String getDataId() {
return (String)param.get("dataId");
return (String) param.get("dataId");
}
public void setDataId(String dataId) {
param.put("dataId", dataId);
}
public String getGroup() {
return (String)param.get("group");
return (String) param.get("group");
}
public void setGroup(String group) {
param.put("group", group);
}
public String getContent() {
return (String)param.get("content");
return (String) param.get("content");
}
public void setContent(String content) {
param.put("content", content);
}
@Override
public Object getParameter(String key) {
return param.get(key);
}
@Override
public IConfigContext getConfigContext() {
return configContext;
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.filter.impl;
import com.alibaba.nacos.api.config.filter.IConfigContext;
@ -22,56 +23,56 @@ import java.util.HashMap;
import java.util.Map;
/**
* Config Response
* Config Response.
*
* @author Nacos
*/
public class ConfigResponse implements IConfigResponse {
private Map<String, Object> param = new HashMap<String, Object>();
private IConfigContext configContext = new ConfigContext();
private final Map<String, Object> param = new HashMap<String, Object>();
private final IConfigContext configContext = new ConfigContext();
public String getTenant() {
return (String)param.get("tenant");
return (String) param.get("tenant");
}
public void setTenant(String tenant) {
param.put("tenant", tenant);
}
public String getDataId() {
return (String)param.get("dataId");
return (String) param.get("dataId");
}
public void setDataId(String dataId) {
param.put("dataId", dataId);
}
public String getGroup() {
return (String)param.get("group");
return (String) param.get("group");
}
public void setGroup(String group) {
param.put("group", group);
}
public String getContent() {
return (String)param.get("content");
return (String) param.get("content");
}
public void setContent(String content) {
param.put("content", content);
}
@Override
public Object getParameter(String key) {
return param.get(key);
}
@Override
public IConfigContext getConfigContext() {
return configContext;
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.http;
import com.alibaba.nacos.api.exception.NacosException;
@ -22,78 +23,87 @@ import com.alibaba.nacos.common.lifecycle.Closeable;
import java.io.IOException;
import java.util.List;
/**
* HttpAgent
* HttpAgent.
*
* @author Nacos
*/
public interface HttpAgent extends Closeable {
/**
* start to get nacos ip list
* @return Nothing.
* start to get nacos ip list.
*
* @throws NacosException on get ip list error.
*/
void start() throws NacosException;
/**
* invoke http get method
* @param path http path
* @param headers http headers
* @param paramValues http paramValues http
* @param encoding http encode
* invoke http get method.
*
* @param path http path
* @param headers http headers
* @param paramValues http paramValues http
* @param encoding http encode
* @param readTimeoutMs http timeout
* @return HttpResult http response
* @throws IOException If an input or output exception occurred
*/
HttpResult httpGet(String path, List<String> headers, List<String> paramValues, String encoding, long readTimeoutMs) throws IOException;
HttpResult httpGet(String path, List<String> headers, List<String> paramValues, String encoding, long readTimeoutMs)
throws IOException;
/**
* invoke http post method
* @param path http path
* @param headers http headers
* @param paramValues http paramValues http
* @param encoding http encode
* invoke http post method.
*
* @param path http path
* @param headers http headers
* @param paramValues http paramValues http
* @param encoding http encode
* @param readTimeoutMs http timeout
* @return HttpResult http response
* @throws IOException If an input or output exception occurred
*/
HttpResult httpPost(String path, List<String> headers, List<String> paramValues, String encoding, long readTimeoutMs) throws IOException;
HttpResult httpPost(String path, List<String> headers, List<String> paramValues, String encoding,
long readTimeoutMs) throws IOException;
/**
* invoke http delete method
* @param path http path
* @param headers http headers
* @param paramValues http paramValues http
* @param encoding http encode
* invoke http delete method.
*
* @param path http path
* @param headers http headers
* @param paramValues http paramValues http
* @param encoding http encode
* @param readTimeoutMs http timeout
* @return HttpResult http response
* @throws IOException If an input or output exception occurred
*/
HttpResult httpDelete(String path, List<String> headers, List<String> paramValues, String encoding, long readTimeoutMs) throws IOException;
HttpResult httpDelete(String path, List<String> headers, List<String> paramValues, String encoding,
long readTimeoutMs) throws IOException;
/**
* get name
* get name.
*
* @return String
*/
String getName();
/**
* get namespace
* get namespace.
*
* @return String
*/
String getNamespace();
/**
* get tenant
* get tenant.
*
* @return String
*/
String getTenant();
/**
* get encode
* get encode.
*
* @return String
*/
String getEncode();

View File

@ -13,11 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* MetricsHttpAgent
*
* @author Nacos
*/
package com.alibaba.nacos.client.config.http;
import com.alibaba.nacos.api.exception.NacosException;
@ -29,25 +25,26 @@ import java.io.IOException;
import java.util.List;
/**
* MetricsHttpAgent
* MetricsHttpAgent.
*
* @author Nacos
*/
public class MetricsHttpAgent implements HttpAgent {
private HttpAgent httpAgent;
private final HttpAgent httpAgent;
public MetricsHttpAgent(HttpAgent httpAgent) {
this.httpAgent = httpAgent;
}
@Override
public void start() throws NacosException {
httpAgent.start();
}
@Override
public HttpResult httpGet(String path, List<String> headers, List<String> paramValues, String encoding, long readTimeoutMs) throws IOException {
public HttpResult httpGet(String path, List<String> headers, List<String> paramValues, String encoding,
long readTimeoutMs) throws IOException {
Histogram.Timer timer = MetricsMonitor.getConfigRequestMonitor("GET", path, "NA");
HttpResult result;
try {
@ -58,12 +55,13 @@ public class MetricsHttpAgent implements HttpAgent {
timer.observeDuration();
timer.close();
}
return result;
}
@Override
public HttpResult httpPost(String path, List<String> headers, List<String> paramValues, String encoding, long readTimeoutMs) throws IOException {
public HttpResult httpPost(String path, List<String> headers, List<String> paramValues, String encoding,
long readTimeoutMs) throws IOException {
Histogram.Timer timer = MetricsMonitor.getConfigRequestMonitor("POST", path, "NA");
HttpResult result;
try {
@ -74,49 +72,50 @@ public class MetricsHttpAgent implements HttpAgent {
timer.observeDuration();
timer.close();
}
return result;
}
@Override
public HttpResult httpDelete(String path, List<String> headers, List<String> paramValues, String encoding, long readTimeoutMs) throws IOException {
public HttpResult httpDelete(String path, List<String> headers, List<String> paramValues, String encoding,
long readTimeoutMs) throws IOException {
Histogram.Timer timer = MetricsMonitor.getConfigRequestMonitor("DELETE", path, "NA");
HttpResult result;
try {
result = httpAgent.httpDelete(path, headers, paramValues, encoding, readTimeoutMs);
} catch (IOException e) {
throw e;
} finally {
timer.observeDuration();
timer.close();
}
return result;
}
@Override
public String getName() {
return httpAgent.getName();
}
@Override
public String getNamespace() {
return httpAgent.getNamespace();
}
@Override
public String getTenant() {
return httpAgent.getTenant();
}
@Override
public String getEncode() {
return httpAgent.getEncode();
}
@Override
public void shutdown() throws NacosException{
public void shutdown() throws NacosException {
httpAgent.shutdown();
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.http;
import com.alibaba.nacos.api.PropertyKeyConst;
@ -22,7 +23,7 @@ import com.alibaba.nacos.client.config.impl.HttpSimpleClient;
import com.alibaba.nacos.client.config.impl.HttpSimpleClient.HttpResult;
import com.alibaba.nacos.client.config.impl.ServerListManager;
import com.alibaba.nacos.client.config.impl.SpasAdapter;
import com.alibaba.nacos.client.identify.STSConfig;
import com.alibaba.nacos.client.identify.StsConfig;
import com.alibaba.nacos.client.security.SecurityProxy;
import com.alibaba.nacos.client.utils.LogUtils;
import com.alibaba.nacos.client.utils.ParamUtil;
@ -45,228 +46,241 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.Callable;
/**
* Server Agent
* Server Agent.
*
* @author water.lyl
*/
public class ServerHttpAgent implements HttpAgent {
private static final Logger LOGGER = LogUtils.logger(ServerHttpAgent.class);
private SecurityProxy securityProxy;
private String namespaceId;
private long securityInfoRefreshIntervalMills = TimeUnit.SECONDS.toMillis(5);
private final long securityInfoRefreshIntervalMills = TimeUnit.SECONDS.toMillis(5);
private ScheduledExecutorService executorService;
/**
* Invoke http get method.
*
* @param path 相对于web应用根/开头
* @param headers
* @param paramValues
* @param encoding
* @param readTimeoutMs
* @return
* @throws IOException
* @param headers headers
* @param paramValues parameters
* @param encoding encoding
* @param readTimeoutMs time out milliseconds
* @return http result
* @throws IOException io exception
*/
@Override
public HttpResult httpGet(String path, List<String> headers, List<String> paramValues, String encoding,
long readTimeoutMs) throws IOException {
long readTimeoutMs) throws IOException {
final long endTime = System.currentTimeMillis() + readTimeoutMs;
final boolean isSSL = false;
final boolean isSsl = false;
injectSecurityInfo(paramValues);
String currentServerAddr = serverListMgr.getCurrentServerAddr();
int maxRetry = this.maxRetry;
do {
try {
List<String> newHeaders = getSpasHeaders(paramValues);
if (headers != null) {
newHeaders.addAll(headers);
}
HttpResult result = HttpSimpleClient.httpGet(
getUrl(currentServerAddr, path), newHeaders, paramValues, encoding,
readTimeoutMs, isSSL);
HttpResult result = HttpSimpleClient
.httpGet(getUrl(currentServerAddr, path), newHeaders, paramValues, encoding, readTimeoutMs,
isSsl);
if (result.code == HttpURLConnection.HTTP_INTERNAL_ERROR
|| result.code == HttpURLConnection.HTTP_BAD_GATEWAY
|| result.code == HttpURLConnection.HTTP_UNAVAILABLE) {
|| result.code == HttpURLConnection.HTTP_BAD_GATEWAY
|| result.code == HttpURLConnection.HTTP_UNAVAILABLE) {
LOGGER.error("[NACOS ConnectException] currentServerAddr: {}, httpCode: {}",
serverListMgr.getCurrentServerAddr(), result.code);
serverListMgr.getCurrentServerAddr(), result.code);
} else {
// Update the currently available server addr
serverListMgr.updateCurrentServerAddr(currentServerAddr);
return result;
}
} catch (ConnectException ce) {
LOGGER.error("[NACOS ConnectException httpGet] currentServerAddr:{}, err : {}", serverListMgr.getCurrentServerAddr(), ce.getMessage());
} catch (SocketTimeoutException stoe) {
LOGGER.error("[NACOS SocketTimeoutException httpGet] currentServerAddr:{} err : {}", serverListMgr.getCurrentServerAddr(), stoe.getMessage());
} catch (IOException ioe) {
LOGGER.error("[NACOS IOException httpGet] currentServerAddr: " + serverListMgr.getCurrentServerAddr(), ioe);
throw ioe;
} catch (ConnectException connectException) {
LOGGER.error("[NACOS ConnectException httpGet] currentServerAddr:{}, err : {}",
serverListMgr.getCurrentServerAddr(), connectException.getMessage());
} catch (SocketTimeoutException socketTimeoutException) {
LOGGER.error("[NACOS SocketTimeoutException httpGet] currentServerAddr:{} err : {}",
serverListMgr.getCurrentServerAddr(), socketTimeoutException.getMessage());
} catch (IOException ioException) {
LOGGER.error("[NACOS IOException httpGet] currentServerAddr: " + serverListMgr.getCurrentServerAddr(),
ioException);
throw ioException;
}
if (serverListMgr.getIterator().hasNext()) {
currentServerAddr = serverListMgr.getIterator().next();
} else {
maxRetry--;
if (maxRetry < 0) {
throw new ConnectException("[NACOS HTTP-GET] The maximum number of tolerable server reconnection errors has been reached");
throw new ConnectException(
"[NACOS HTTP-GET] The maximum number of tolerable server reconnection errors has been reached");
}
serverListMgr.refreshCurrentServerAddr();
}
} while (System.currentTimeMillis() <= endTime);
LOGGER.error("no available server");
throw new ConnectException("no available server");
}
@Override
public HttpResult httpPost(String path, List<String> headers, List<String> paramValues, String encoding,
long readTimeoutMs) throws IOException {
long readTimeoutMs) throws IOException {
final long endTime = System.currentTimeMillis() + readTimeoutMs;
boolean isSSL = false;
boolean isSsl = false;
injectSecurityInfo(paramValues);
String currentServerAddr = serverListMgr.getCurrentServerAddr();
int maxRetry = this.maxRetry;
do {
try {
List<String> newHeaders = getSpasHeaders(paramValues);
if (headers != null) {
newHeaders.addAll(headers);
}
HttpResult result = HttpSimpleClient.httpPost(
getUrl(currentServerAddr, path), newHeaders, paramValues, encoding,
readTimeoutMs, isSSL);
HttpResult result = HttpSimpleClient
.httpPost(getUrl(currentServerAddr, path), newHeaders, paramValues, encoding, readTimeoutMs,
isSsl);
if (result.code == HttpURLConnection.HTTP_INTERNAL_ERROR
|| result.code == HttpURLConnection.HTTP_BAD_GATEWAY
|| result.code == HttpURLConnection.HTTP_UNAVAILABLE) {
LOGGER.error("[NACOS ConnectException] currentServerAddr: {}, httpCode: {}",
currentServerAddr, result.code);
|| result.code == HttpURLConnection.HTTP_BAD_GATEWAY
|| result.code == HttpURLConnection.HTTP_UNAVAILABLE) {
LOGGER.error("[NACOS ConnectException] currentServerAddr: {}, httpCode: {}", currentServerAddr,
result.code);
} else {
// Update the currently available server addr
serverListMgr.updateCurrentServerAddr(currentServerAddr);
return result;
}
} catch (ConnectException ce) {
LOGGER.error("[NACOS ConnectException httpPost] currentServerAddr: {}, err : {}", currentServerAddr, ce.getMessage());
} catch (SocketTimeoutException stoe) {
LOGGER.error("[NACOS SocketTimeoutException httpPost] currentServerAddr: {} err : {}", currentServerAddr, stoe.getMessage());
} catch (ConnectException connectException) {
LOGGER.error("[NACOS ConnectException httpPost] currentServerAddr: {}, err : {}", currentServerAddr,
connectException.getMessage());
} catch (SocketTimeoutException socketTimeoutException) {
LOGGER.error("[NACOS SocketTimeoutException httpPost] currentServerAddr: {} err : {}",
currentServerAddr, socketTimeoutException.getMessage());
} catch (IOException ioe) {
LOGGER.error("[NACOS IOException httpPost] currentServerAddr: " + currentServerAddr, ioe);
throw ioe;
}
if (serverListMgr.getIterator().hasNext()) {
currentServerAddr = serverListMgr.getIterator().next();
} else {
maxRetry--;
if (maxRetry < 0) {
throw new ConnectException("[NACOS HTTP-POST] The maximum number of tolerable server reconnection errors has been reached");
throw new ConnectException(
"[NACOS HTTP-POST] The maximum number of tolerable server reconnection errors has been reached");
}
serverListMgr.refreshCurrentServerAddr();
}
} while (System.currentTimeMillis() <= endTime);
LOGGER.error("no available server, currentServerAddr : {}", currentServerAddr);
throw new ConnectException("no available server, currentServerAddr : " + currentServerAddr);
}
@Override
public HttpResult httpDelete(String path, List<String> headers, List<String> paramValues, String encoding,
long readTimeoutMs) throws IOException {
long readTimeoutMs) throws IOException {
final long endTime = System.currentTimeMillis() + readTimeoutMs;
boolean isSSL = false;
boolean isSsl = false;
injectSecurityInfo(paramValues);
String currentServerAddr = serverListMgr.getCurrentServerAddr();
int maxRetry = this.maxRetry;
do {
try {
List<String> newHeaders = getSpasHeaders(paramValues);
if (headers != null) {
newHeaders.addAll(headers);
}
HttpResult result = HttpSimpleClient.httpDelete(
getUrl(currentServerAddr, path), newHeaders, paramValues, encoding,
readTimeoutMs, isSSL);
HttpResult result = HttpSimpleClient
.httpDelete(getUrl(currentServerAddr, path), newHeaders, paramValues, encoding, readTimeoutMs,
isSsl);
if (result.code == HttpURLConnection.HTTP_INTERNAL_ERROR
|| result.code == HttpURLConnection.HTTP_BAD_GATEWAY
|| result.code == HttpURLConnection.HTTP_UNAVAILABLE) {
|| result.code == HttpURLConnection.HTTP_BAD_GATEWAY
|| result.code == HttpURLConnection.HTTP_UNAVAILABLE) {
LOGGER.error("[NACOS ConnectException] currentServerAddr: {}, httpCode: {}",
serverListMgr.getCurrentServerAddr(), result.code);
serverListMgr.getCurrentServerAddr(), result.code);
} else {
// Update the currently available server addr
serverListMgr.updateCurrentServerAddr(currentServerAddr);
return result;
}
} catch (ConnectException ce) {
ce.printStackTrace();
LOGGER.error("[NACOS ConnectException httpDelete] currentServerAddr:{}, err : {}", serverListMgr.getCurrentServerAddr(), ce.getMessage());
} catch (ConnectException connectException) {
connectException.printStackTrace();
LOGGER.error("[NACOS ConnectException httpDelete] currentServerAddr:{}, err : {}",
serverListMgr.getCurrentServerAddr(), connectException.getMessage());
} catch (SocketTimeoutException stoe) {
stoe.printStackTrace();
LOGGER.error("[NACOS SocketTimeoutException httpDelete] currentServerAddr:{} err : {}", serverListMgr.getCurrentServerAddr(), stoe.getMessage());
LOGGER.error("[NACOS SocketTimeoutException httpDelete] currentServerAddr:{} err : {}",
serverListMgr.getCurrentServerAddr(), stoe.getMessage());
} catch (IOException ioe) {
LOGGER.error("[NACOS IOException httpDelete] currentServerAddr: " + serverListMgr.getCurrentServerAddr(), ioe);
LOGGER.error(
"[NACOS IOException httpDelete] currentServerAddr: " + serverListMgr.getCurrentServerAddr(),
ioe);
throw ioe;
}
if (serverListMgr.getIterator().hasNext()) {
currentServerAddr = serverListMgr.getIterator().next();
} else {
maxRetry--;
if (maxRetry < 0) {
throw new ConnectException("[NACOS HTTP-DELETE] The maximum number of tolerable server reconnection errors has been reached");
throw new ConnectException(
"[NACOS HTTP-DELETE] The maximum number of tolerable server reconnection errors has been reached");
}
serverListMgr.refreshCurrentServerAddr();
}
} while (System.currentTimeMillis() <= endTime);
LOGGER.error("no available server");
throw new ConnectException("no available server");
}
private String getUrl(String serverAddr, String relativePath) {
String contextPath = serverListMgr.getContentPath().startsWith("/") ?
serverListMgr.getContentPath() : "/" + serverListMgr.getContentPath();
String contextPath = serverListMgr.getContentPath().startsWith("/") ? serverListMgr.getContentPath()
: "/" + serverListMgr.getContentPath();
return serverAddr + contextPath + relativePath;
}
public static String getAppname() {
return ParamUtil.getAppName();
}
public ServerHttpAgent(ServerListManager mgr) {
this.serverListMgr = mgr;
}
public ServerHttpAgent(ServerListManager mgr, Properties properties) {
this.serverListMgr = mgr;
init(properties);
}
public ServerHttpAgent(Properties properties) throws NacosException {
this.serverListMgr = new ServerListManager(properties);
this.securityProxy = new SecurityProxy(properties);
this.namespaceId = properties.getProperty(PropertyKeyConst.NAMESPACE);
init(properties);
this.securityProxy.login(this.serverListMgr.getServerUrls());
// init executorService
this.executorService = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
@Override
@ -277,16 +291,16 @@ public class ServerHttpAgent implements HttpAgent {
return t;
}
});
this.executorService.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
securityProxy.login(serverListMgr.getServerUrls());
}
}, 0, this.securityInfoRefreshIntervalMills, TimeUnit.MILLISECONDS);
}
private void injectSecurityInfo(List<String> params) {
if (StringUtils.isNotBlank(securityProxy.getAccessToken())) {
params.add(Constants.ACCESS_TOKEN);
@ -297,35 +311,36 @@ public class ServerHttpAgent implements HttpAgent {
params.add(namespaceId);
}
}
private void init(Properties properties) {
initEncode(properties);
initAkSk(properties);
initMaxRetry(properties);
}
private void initEncode(Properties properties) {
encode = TemplateUtils.stringEmptyAndThenExecute(properties.getProperty(PropertyKeyConst.ENCODE), new Callable<String>() {
@Override
public String call() throws Exception {
return Constants.ENCODE;
}
});
encode = TemplateUtils
.stringEmptyAndThenExecute(properties.getProperty(PropertyKeyConst.ENCODE), new Callable<String>() {
@Override
public String call() throws Exception {
return Constants.ENCODE;
}
});
}
private void initAkSk(Properties properties) {
String ramRoleName = properties.getProperty(PropertyKeyConst.RAM_ROLE_NAME);
if (!StringUtils.isBlank(ramRoleName)) {
STSConfig.getInstance().setRamRoleName(ramRoleName);
StsConfig.getInstance().setRamRoleName(ramRoleName);
}
String ak = properties.getProperty(PropertyKeyConst.ACCESS_KEY);
if (StringUtils.isBlank(ak)) {
accessKey = SpasAdapter.getAk();
} else {
accessKey = ak;
}
String sk = properties.getProperty(PropertyKeyConst.SECRET_KEY);
if (StringUtils.isBlank(sk)) {
secretKey = SpasAdapter.getSk();
@ -333,27 +348,27 @@ public class ServerHttpAgent implements HttpAgent {
secretKey = sk;
}
}
private void initMaxRetry(Properties properties) {
maxRetry = ConvertUtils.toInt(String.valueOf(properties.get(PropertyKeyConst.MAX_RETRY)), Constants.MAX_RETRY);
}
@Override
public void start() throws NacosException {
serverListMgr.start();
}
private List<String> getSpasHeaders(List<String> paramValues) throws IOException {
List<String> newHeaders = new ArrayList<String>();
// STS 临时凭证鉴权的优先级高于 AK/SK 鉴权
if (STSConfig.getInstance().isSTSOn()) {
STSCredential sTSCredential = getSTSCredential();
accessKey = sTSCredential.accessKeyId;
secretKey = sTSCredential.accessKeySecret;
if (StsConfig.getInstance().isStsOn()) {
StsCredential stsCredential = getStsCredential();
accessKey = stsCredential.accessKeyId;
secretKey = stsCredential.accessKeySecret;
newHeaders.add("Spas-SecurityToken");
newHeaders.add(sTSCredential.securityToken);
newHeaders.add(stsCredential.securityToken);
}
if (StringUtils.isNotEmpty(accessKey) && StringUtils.isNotEmpty(secretKey)) {
newHeaders.add("Spas-AccessKey");
newHeaders.add(accessKey);
@ -364,32 +379,33 @@ public class ServerHttpAgent implements HttpAgent {
}
return newHeaders;
}
private STSCredential getSTSCredential() throws IOException {
boolean cacheSecurityCredentials = STSConfig.getInstance().isCacheSecurityCredentials();
if (cacheSecurityCredentials && sTSCredential != null) {
private StsCredential getStsCredential() throws IOException {
boolean cacheSecurityCredentials = StsConfig.getInstance().isCacheSecurityCredentials();
if (cacheSecurityCredentials && stsCredential != null) {
long currentTime = System.currentTimeMillis();
long expirationTime = sTSCredential.expiration.getTime();
int timeToRefreshInMillisecond = STSConfig.getInstance().getTimeToRefreshInMillisecond();
long expirationTime = stsCredential.expiration.getTime();
int timeToRefreshInMillisecond = StsConfig.getInstance().getTimeToRefreshInMillisecond();
if (expirationTime - currentTime > timeToRefreshInMillisecond) {
return sTSCredential;
return stsCredential;
}
}
String stsResponse = getSTSResponse();
STSCredential stsCredentialTmp = JacksonUtils.toObj(stsResponse, new TypeReference<STSCredential>() {
});
sTSCredential = stsCredentialTmp;
LOGGER.info("[getSTSCredential] code:{}, accessKeyId:{}, lastUpdated:{}, expiration:{}", sTSCredential.getCode(),
sTSCredential.getAccessKeyId(), sTSCredential.getLastUpdated(), sTSCredential.getExpiration());
return sTSCredential;
String stsResponse = getStsResponse();
StsCredential stsCredentialTmp = JacksonUtils.toObj(stsResponse, new TypeReference<StsCredential>() {
});
stsCredential = stsCredentialTmp;
LOGGER.info("[getSTSCredential] code:{}, accessKeyId:{}, lastUpdated:{}, expiration:{}",
stsCredential.getCode(), stsCredential.getAccessKeyId(), stsCredential.getLastUpdated(),
stsCredential.getExpiration());
return stsCredential;
}
private static String getSTSResponse() throws IOException {
String securityCredentials = STSConfig.getInstance().getSecurityCredentials();
private static String getStsResponse() throws IOException {
String securityCredentials = StsConfig.getInstance().getSecurityCredentials();
if (securityCredentials != null) {
return securityCredentials;
}
String securityCredentialsUrl = STSConfig.getInstance().getSecurityCredentialsUrl();
String securityCredentialsUrl = StsConfig.getInstance().getSecurityCredentialsUrl();
HttpURLConnection conn = null;
int respCode;
String response;
@ -415,88 +431,93 @@ public class ServerHttpAgent implements HttpAgent {
return response;
}
LOGGER.error("can not get security credentials, securityCredentialsUrl: {}, responseCode: {}, response: {}",
securityCredentialsUrl, respCode, response);
securityCredentialsUrl, respCode, response);
throw new IOException(
"can not get security credentials, responseCode: " + respCode + ", response: " + response);
"can not get security credentials, responseCode: " + respCode + ", response: " + response);
}
@Override
public String getName() {
return serverListMgr.getName();
}
@Override
public String getNamespace() {
return serverListMgr.getNamespace();
}
@Override
public String getTenant() {
return serverListMgr.getTenant();
}
@Override
public String getEncode() {
return encode;
}
@Override
public void shutdown() throws NacosException{
public void shutdown() throws NacosException {
String className = this.getClass().getName();
LOGGER.info("{} do shutdown begin", className);
ThreadUtils.shutdownThreadPool(executorService, LOGGER);
LOGGER.info("{} do shutdown stop", className);
}
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
private static class STSCredential {
private static class StsCredential {
@JsonProperty(value = "AccessKeyId")
private String accessKeyId;
@JsonProperty(value = "AccessKeySecret")
private String accessKeySecret;
@JsonProperty(value = "Expiration")
private Date expiration;
@JsonProperty(value = "SecurityToken")
private String securityToken;
@JsonProperty(value = "LastUpdated")
private Date lastUpdated;
@JsonProperty(value = "Code")
private String code;
public String getAccessKeyId() {
return accessKeyId;
}
public Date getExpiration() {
return expiration;
}
public Date getLastUpdated() {
return lastUpdated;
}
public String getCode() {
return code;
}
@Override
public String toString() {
return "STSCredential{" +
"accessKeyId='" + accessKeyId + '\'' +
", accessKeySecret='" + accessKeySecret + '\'' +
", expiration=" + expiration +
", securityToken='" + securityToken + '\'' +
", lastUpdated=" + lastUpdated +
", code='" + code + '\'' +
'}';
return "STSCredential{" + "accessKeyId='" + accessKeyId + '\'' + ", accessKeySecret='" + accessKeySecret
+ '\'' + ", expiration=" + expiration + ", securityToken='" + securityToken + '\''
+ ", lastUpdated=" + lastUpdated + ", code='" + code + '\'' + '}';
}
}
private String accessKey;
private String secretKey;
private String encode;
private int maxRetry = 3;
private volatile STSCredential sTSCredential;
private volatile StsCredential stsCredential;
final ServerListManager serverListMgr;
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.impl;
import com.alibaba.nacos.api.config.ConfigChangeItem;
@ -20,32 +21,31 @@ import com.alibaba.nacos.api.config.PropertyChangeType;
import com.alibaba.nacos.api.config.listener.ConfigChangeParser;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* AbstractConfigChangeParser
* AbstractConfigChangeParser.
*
* @author rushsky518
*/
public abstract class AbstractConfigChangeParser implements ConfigChangeParser {
private String configType;
private final String configType;
public AbstractConfigChangeParser(String configType) {
this.configType = configType;
}
@Override
public boolean isResponsibleFor(String type) {
return this.configType.equalsIgnoreCase(type);
}
protected Map<String, ConfigChangeItem> filterChangeData(Map oldMap, Map newMap) {
Map<String, ConfigChangeItem> result = new HashMap<String, ConfigChangeItem>(16);
for (Iterator<Map.Entry<String, Object>> entryItr = oldMap.entrySet().iterator(); entryItr.hasNext();) {
Map.Entry<String, Object> e = entryItr.next();
for (Map.Entry<String, Object> e : (Iterable<Map.Entry<String, Object>>) oldMap.entrySet()) {
ConfigChangeItem cci;
if (newMap.containsKey(e.getKey())) {
if (newMap.containsKey(e.getKey())) {
if (e.getValue().equals(newMap.get(e.getKey()))) {
continue;
}
@ -55,20 +55,19 @@ public abstract class AbstractConfigChangeParser implements ConfigChangeParser {
cci = new ConfigChangeItem(e.getKey(), e.getValue().toString(), null);
cci.setType(PropertyChangeType.DELETED);
}
result.put(e.getKey(), cci);
}
for (Iterator<Map.Entry<String, Object>> entryItr = newMap.entrySet().iterator(); entryItr.hasNext();) {
Map.Entry<String, Object> e = entryItr.next();
for (Map.Entry<String, Object> e : (Iterable<Map.Entry<String, Object>>) newMap.entrySet()) {
if (!oldMap.containsKey(e.getKey())) {
ConfigChangeItem cci = new ConfigChangeItem(e.getKey(), null, e.getValue().toString());
cci.setType(PropertyChangeType.ADDED);
result.put(e.getKey(), cci);
}
}
return result;
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.impl;
import com.alibaba.nacos.api.common.Constants;
@ -23,9 +24,9 @@ import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.client.config.filter.impl.ConfigFilterChainManager;
import com.alibaba.nacos.client.config.filter.impl.ConfigResponse;
import com.alibaba.nacos.client.config.listener.impl.AbstractConfigChangeListener;
import com.alibaba.nacos.common.utils.MD5Utils;
import com.alibaba.nacos.client.utils.LogUtils;
import com.alibaba.nacos.client.utils.TenantUtil;
import com.alibaba.nacos.common.utils.MD5Utils;
import org.slf4j.Logger;
import java.util.ArrayList;
@ -34,50 +35,49 @@ import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Listner Management
* Listener Management.
*
* @author Nacos
*/
public class CacheData {
private static final Logger LOGGER = LogUtils.logger(CacheData.class);
public boolean isInitializing() {
return isInitializing;
}
public void setInitializing(boolean isInitializing) {
this.isInitializing = isInitializing;
}
public String getMd5() {
return md5;
}
public String getTenant() {
return tenant;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
this.md5 = getMd5String(this.content);
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
/**
* Add listener
* if CacheData already set new content, Listener should init lastCallMd5 by CacheData.md5
* Add listener if CacheData already set new content, Listener should init lastCallMd5 by CacheData.md5
*
* @param listener listener
*/
@ -85,27 +85,34 @@ public class CacheData {
if (null == listener) {
throw new IllegalArgumentException("listener is null");
}
ManagerListenerWrap wrap = (listener instanceof AbstractConfigChangeListener) ?
new ManagerListenerWrap(listener, md5, content) : new ManagerListenerWrap(listener, md5);
ManagerListenerWrap wrap =
(listener instanceof AbstractConfigChangeListener) ? new ManagerListenerWrap(listener, md5, content)
: new ManagerListenerWrap(listener, md5);
if (listeners.addIfAbsent(wrap)) {
LOGGER.info("[{}] [add-listener] ok, tenant={}, dataId={}, group={}, cnt={}", name, tenant, dataId, group,
listeners.size());
listeners.size());
}
}
/**
* Remove listener.
*
* @param listener listener
*/
public void removeListener(Listener listener) {
if (null == listener) {
throw new IllegalArgumentException("listener is null");
}
ManagerListenerWrap wrap = new ManagerListenerWrap(listener);
if (listeners.remove(wrap)) {
LOGGER.info("[{}] [remove-listener] ok, dataId={}, group={}, cnt={}", name, dataId, group, listeners.size());
LOGGER.info("[{}] [remove-listener] ok, dataId={}, group={}, cnt={}", name, dataId, group,
listeners.size());
}
}
/**
* 返回监听器列表上的迭代器只读保证不返回NULL
* 返回监听器列表上的迭代器只读保证不返回NULL.
*/
public List<Listener> getListeners() {
List<Listener> result = new ArrayList<Listener>();
@ -114,34 +121,34 @@ public class CacheData {
}
return result;
}
public long getLocalConfigInfoVersion() {
return localConfigLastModified;
}
public void setLocalConfigInfoVersion(long localConfigLastModified) {
this.localConfigLastModified = localConfigLastModified;
}
public boolean isUseLocalConfigInfo() {
return isUseLocalConfig;
}
public void setUseLocalConfigInfo(boolean useLocalConfigInfo) {
this.isUseLocalConfig = useLocalConfigInfo;
if (!useLocalConfigInfo) {
localConfigLastModified = -1;
}
}
public int getTaskId() {
return taskId;
}
public void setTaskId(int taskId) {
this.taskId = taskId;
}
@Override
public int hashCode() {
final int prime = 31;
@ -150,7 +157,7 @@ public class CacheData {
result = prime * result + ((group == null) ? 0 : group.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (null == obj || obj.getClass() != getClass()) {
@ -162,12 +169,12 @@ public class CacheData {
CacheData other = (CacheData) obj;
return dataId.equals(other.dataId) && group.equals(other.group);
}
@Override
public String toString() {
return "CacheData [" + dataId + ", " + group + "]";
}
void checkListenerMd5() {
for (ManagerListenerWrap wrap : listeners) {
if (!md5.equals(wrap.lastCallMd5)) {
@ -175,11 +182,11 @@ public class CacheData {
}
}
}
private void safeNotifyListener(final String dataId, final String group, final String content, final String type,
final String md5, final ManagerListenerWrap listenerWrap) {
final String md5, final ManagerListenerWrap listenerWrap) {
final Listener listener = listenerWrap.listener;
Runnable job = new Runnable() {
@Override
public void run() {
@ -193,7 +200,7 @@ public class CacheData {
}
// 执行回调之前先将线程classloader设置为具体webapp的classloader以免回调方法中调用spi接口是出现异常或错用多应用部署才会有该问题
Thread.currentThread().setContextClassLoader(appClassLoader);
ConfigResponse cr = new ConfigResponse();
cr.setDataId(dataId);
cr.setGroup(group);
@ -201,30 +208,31 @@ public class CacheData {
configFilterChainManager.doFilter(null, cr);
String contentTmp = cr.getContent();
listener.receiveConfigInfo(contentTmp);
// compare lastContent and content
if (listener instanceof AbstractConfigChangeListener) {
Map data = ConfigChangeHandler.getInstance().parseChangeData(listenerWrap.lastContent, content, type);
Map data = ConfigChangeHandler.getInstance()
.parseChangeData(listenerWrap.lastContent, content, type);
ConfigChangeEvent event = new ConfigChangeEvent(data);
((AbstractConfigChangeListener)listener).receiveConfigChange(event);
((AbstractConfigChangeListener) listener).receiveConfigChange(event);
listenerWrap.lastContent = content;
}
listenerWrap.lastCallMd5 = md5;
LOGGER.info("[{}] [notify-ok] dataId={}, group={}, md5={}, listener={} ", name, dataId, group, md5,
listener);
} catch (NacosException de) {
LOGGER.error("[{}] [notify-error] dataId={}, group={}, md5={}, listener={} errCode={} errMsg={}", name,
dataId, group, md5, listener, de.getErrCode(), de.getErrMsg());
listener);
} catch (NacosException ex) {
LOGGER.error("[{}] [notify-error] dataId={}, group={}, md5={}, listener={} errCode={} errMsg={}",
name, dataId, group, md5, listener, ex.getErrCode(), ex.getErrMsg());
} catch (Throwable t) {
LOGGER.error("[{}] [notify-error] dataId={}, group={}, md5={}, listener={} tx={}", name, dataId, group,
md5, listener, t.getCause());
LOGGER.error("[{}] [notify-error] dataId={}, group={}, md5={}, listener={} tx={}", name, dataId,
group, md5, listener, t.getCause());
} finally {
Thread.currentThread().setContextClassLoader(myClassLoader);
}
}
};
final long startNotify = System.currentTimeMillis();
try {
if (null != listener.getExecutor()) {
@ -233,25 +241,24 @@ public class CacheData {
job.run();
}
} catch (Throwable t) {
LOGGER.error("[{}] [notify-error] dataId={}, group={}, md5={}, listener={} throwable={}", name, dataId, group,
md5, listener, t.getCause());
LOGGER.error("[{}] [notify-error] dataId={}, group={}, md5={}, listener={} throwable={}", name, dataId,
group, md5, listener, t.getCause());
}
final long finishNotify = System.currentTimeMillis();
LOGGER.info("[{}] [notify-listener] time cost={}ms in ClientWorker, dataId={}, group={}, md5={}, listener={} ",
name, (finishNotify - startNotify), dataId, group, md5, listener);
name, (finishNotify - startNotify), dataId, group, md5, listener);
}
static public String getMd5String(String config) {
public static String getMd5String(String config) {
return (null == config) ? Constants.NULL : MD5Utils.md5Hex(config, Constants.ENCODE);
}
private String loadCacheContentFromDiskLocal(String name, String dataId, String group, String tenant) {
String content = LocalConfigInfoProcessor.getFailover(name, dataId, group, tenant);
content = (null != content) ? content
: LocalConfigInfoProcessor.getSnapshot(name, dataId, group, tenant);
content = (null != content) ? content : LocalConfigInfoProcessor.getSnapshot(name, dataId, group, tenant);
return content;
}
public CacheData(ConfigFilterChainManager configFilterChainManager, String name, String dataId, String group) {
if (null == dataId || null == group) {
throw new IllegalArgumentException("dataId=" + dataId + ", group=" + group);
@ -266,9 +273,9 @@ public class CacheData {
this.content = loadCacheContentFromDiskLocal(name, dataId, group, tenant);
this.md5 = getMd5String(content);
}
public CacheData(ConfigFilterChainManager configFilterChainManager, String name, String dataId, String group,
String tenant) {
String tenant) {
if (null == dataId || null == group) {
throw new IllegalArgumentException("dataId=" + dataId + ", group=" + group);
}
@ -282,66 +289,80 @@ public class CacheData {
this.content = loadCacheContentFromDiskLocal(name, dataId, group, tenant);
this.md5 = getMd5String(content);
}
// ==================
private final String name;
private final ConfigFilterChainManager configFilterChainManager;
public final String dataId;
public final String group;
public final String tenant;
private final CopyOnWriteArrayList<ManagerListenerWrap> listeners;
private volatile String md5;
/**
* whether use local config
* whether use local config.
*/
private volatile boolean isUseLocalConfig = false;
/**
* last modify time
* last modify time.
*/
private volatile long localConfigLastModified;
private volatile String content;
private int taskId;
private volatile boolean isInitializing = true;
private String type;
}
class ManagerListenerWrap {
final Listener listener;
String lastCallMd5 = CacheData.getMd5String(null);
String lastContent = null;
ManagerListenerWrap(Listener listener) {
this.listener = listener;
}
ManagerListenerWrap(Listener listener, String md5) {
this.listener = listener;
this.lastCallMd5 = md5;
}
ManagerListenerWrap(Listener listener, String md5, String lastContent) {
this.listener = listener;
this.lastCallMd5 = md5;
this.lastContent = lastContent;
}
@Override
public boolean equals(Object obj) {
if (null == obj || obj.getClass() != getClass()) {
return false;
private static class ManagerListenerWrap {
final Listener listener;
String lastCallMd5 = CacheData.getMd5String(null);
String lastContent = null;
ManagerListenerWrap(Listener listener) {
this.listener = listener;
}
if (obj == this) {
return true;
ManagerListenerWrap(Listener listener, String md5) {
this.listener = listener;
this.lastCallMd5 = md5;
}
ManagerListenerWrap other = (ManagerListenerWrap) obj;
return listener.equals(other.listener);
ManagerListenerWrap(Listener listener, String md5, String lastContent) {
this.listener = listener;
this.lastCallMd5 = md5;
this.lastContent = lastContent;
}
@Override
public boolean equals(Object obj) {
if (null == obj || obj.getClass() != getClass()) {
return false;
}
if (obj == this) {
return true;
}
ManagerListenerWrap other = (ManagerListenerWrap) obj;
return listener.equals(other.listener);
}
@Override
public int hashCode() {
return super.hashCode();
}
}
@Override
public int hashCode() {
return super.hashCode();
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.impl;
import com.alibaba.nacos.api.PropertyKeyConst;
@ -25,14 +26,14 @@ import com.alibaba.nacos.client.config.filter.impl.ConfigFilterChainManager;
import com.alibaba.nacos.client.config.http.HttpAgent;
import com.alibaba.nacos.client.config.impl.HttpSimpleClient.HttpResult;
import com.alibaba.nacos.client.config.utils.ContentUtils;
import com.alibaba.nacos.common.lifecycle.Closeable;
import com.alibaba.nacos.common.utils.ConvertUtils;
import com.alibaba.nacos.common.utils.MD5Utils;
import com.alibaba.nacos.client.monitor.MetricsMonitor;
import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import com.alibaba.nacos.client.utils.LogUtils;
import com.alibaba.nacos.client.utils.ParamUtil;
import com.alibaba.nacos.client.utils.TenantUtil;
import com.alibaba.nacos.common.lifecycle.Closeable;
import com.alibaba.nacos.common.utils.ConvertUtils;
import com.alibaba.nacos.common.utils.MD5Utils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.common.utils.ThreadUtils;
import org.slf4j.Logger;
@ -41,13 +42,13 @@ import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URLDecoder;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@ -55,19 +56,26 @@ import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import static com.alibaba.nacos.api.common.Constants.CONFIG_TYPE;
import static com.alibaba.nacos.api.common.Constants.LINE_SEPARATOR;
import static com.alibaba.nacos.api.common.Constants.WORD_SEPARATOR;
import static com.alibaba.nacos.api.common.Constants.CONFIG_TYPE;
/**
* Longpolling
* Long polling.
*
* @author Nacos
*/
public class ClientWorker implements Closeable {
private static final Logger LOGGER = LogUtils.logger(ClientWorker.class);
/**
* Add listeners for data.
*
* @param dataId dataId of data
* @param group group of data
* @param listeners listeners
*/
public void addListeners(String dataId, String group, List<? extends Listener> listeners) {
group = null2defaultGroup(group);
CacheData cache = addCacheDataIfAbsent(dataId, group);
@ -75,7 +83,14 @@ public class ClientWorker implements Closeable {
cache.addListener(listener);
}
}
/**
* Remove listener.
*
* @param dataId dataId of data
* @param group group of data
* @param listener listener
*/
public void removeListener(String dataId, String group, Listener listener) {
group = null2defaultGroup(group);
CacheData cache = getCache(dataId, group);
@ -86,8 +101,17 @@ public class ClientWorker implements Closeable {
}
}
}
public void addTenantListeners(String dataId, String group, List<? extends Listener> listeners) throws NacosException {
/**
* Add listeners for tenant.
*
* @param dataId dataId of data
* @param group group of data
* @param listeners listeners
* @throws NacosException nacos exception
*/
public void addTenantListeners(String dataId, String group, List<? extends Listener> listeners)
throws NacosException {
group = null2defaultGroup(group);
String tenant = agent.getTenant();
CacheData cache = addCacheDataIfAbsent(dataId, group, tenant);
@ -95,8 +119,18 @@ public class ClientWorker implements Closeable {
cache.addListener(listener);
}
}
public void addTenantListenersWithContent(String dataId, String group, String content, List<? extends Listener> listeners) throws NacosException {
/**
* Add listeners for tenant with content.
*
* @param dataId dataId of data
* @param group group of data
* @param content content
* @param listeners listeners
* @throws NacosException nacos exception
*/
public void addTenantListenersWithContent(String dataId, String group, String content,
List<? extends Listener> listeners) throws NacosException {
group = null2defaultGroup(group);
String tenant = agent.getTenant();
CacheData cache = addCacheDataIfAbsent(dataId, group, tenant);
@ -105,7 +139,14 @@ public class ClientWorker implements Closeable {
cache.addListener(listener);
}
}
/**
* Remove listeners for tenant.
*
* @param dataId dataId of data
* @param group group of data
* @param listener listener
*/
public void removeTenantListener(String dataId, String group, Listener listener) {
group = null2defaultGroup(group);
String tenant = agent.getTenant();
@ -117,8 +158,8 @@ public class ClientWorker implements Closeable {
}
}
}
void removeCache(String dataId, String group) {
private void removeCache(String dataId, String group) {
String groupKey = GroupKey.getKey(dataId, group);
synchronized (cacheMap) {
Map<String, CacheData> copy = new HashMap<String, CacheData>(cacheMap.get());
@ -126,10 +167,10 @@ public class ClientWorker implements Closeable {
cacheMap.set(copy);
}
LOGGER.info("[{}] [unsubscribe] {}", this.agent.getName(), groupKey);
MetricsMonitor.getListenConfigCountMonitor().set(cacheMap.get().size());
}
void removeCache(String dataId, String group, String tenant) {
String groupKey = GroupKey.getKeyTenant(dataId, group, tenant);
synchronized (cacheMap) {
@ -138,19 +179,26 @@ public class ClientWorker implements Closeable {
cacheMap.set(copy);
}
LOGGER.info("[{}] [unsubscribe] {}", agent.getName(), groupKey);
MetricsMonitor.getListenConfigCountMonitor().set(cacheMap.get().size());
}
/**
* Add cache data if absent.
*
* @param dataId data id if data
* @param group group of data
* @return cache data
*/
public CacheData addCacheDataIfAbsent(String dataId, String group) {
CacheData cache = getCache(dataId, group);
if (null != cache) {
return cache;
}
String key = GroupKey.getKey(dataId, group);
cache = new CacheData(configFilterChainManager, agent.getName(), dataId, group);
synchronized (cacheMap) {
CacheData cacheFromMap = getCache(dataId, group);
// multiple listeners on the same dataid+group and race condition,so double check again
@ -163,19 +211,27 @@ public class ClientWorker implements Closeable {
int taskId = cacheMap.get().size() / (int) ParamUtil.getPerTaskConfigSize();
cache.setTaskId(taskId);
}
Map<String, CacheData> copy = new HashMap<String, CacheData>(cacheMap.get());
copy.put(key, cache);
cacheMap.set(copy);
}
LOGGER.info("[{}] [subscribe] {}", this.agent.getName(), key);
MetricsMonitor.getListenConfigCountMonitor().set(cacheMap.get().size());
return cache;
}
/**
* Add cache data if absent.
*
* @param dataId data id if data
* @param group group of data
* @param tenant tenant of data
* @return cache data
*/
public CacheData addCacheDataIfAbsent(String dataId, String group, String tenant) throws NacosException {
CacheData cache = getCache(dataId, group, tenant);
if (null != cache) {
@ -199,36 +255,36 @@ public class ClientWorker implements Closeable {
cache.setContent(ct[0]);
}
}
Map<String, CacheData> copy = new HashMap<String, CacheData>(this.cacheMap.get());
copy.put(key, cache);
cacheMap.set(copy);
}
LOGGER.info("[{}] [subscribe] {}", agent.getName(), key);
MetricsMonitor.getListenConfigCountMonitor().set(cacheMap.get().size());
return cache;
}
public CacheData getCache(String dataId, String group) {
return getCache(dataId, group, TenantUtil.getUserTenantForAcm());
}
public CacheData getCache(String dataId, String group, String tenant) {
if (null == dataId || null == group) {
throw new IllegalArgumentException();
}
return cacheMap.get().get(GroupKey.getKeyTenant(dataId, group, tenant));
}
public String[] getServerConfig(String dataId, String group, String tenant, long readTimeout)
throws NacosException {
throws NacosException {
String[] ct = new String[2];
if (StringUtils.isBlank(group)) {
group = Constants.DEFAULT_GROUP;
}
HttpResult result = null;
try {
List<String> params = null;
@ -239,13 +295,13 @@ public class ClientWorker implements Closeable {
}
result = agent.httpGet(Constants.CONFIG_CONTROLLER_PATH, null, params, agent.getEncode(), readTimeout);
} catch (IOException e) {
String message = String.format(
"[%s] [sub-server] get server config exception, dataId=%s, group=%s, tenant=%s", agent.getName(),
dataId, group, tenant);
String message = String
.format("[%s] [sub-server] get server config exception, dataId=%s, group=%s, tenant=%s",
agent.getName(), dataId, group, tenant);
LOGGER.error(message, e);
throw new NacosException(NacosException.SERVER_ERROR, e);
}
switch (result.code) {
case HttpURLConnection.HTTP_OK:
LocalConfigInfoProcessor.saveSnapshot(agent.getName(), dataId, group, tenant, result.content);
@ -261,68 +317,74 @@ public class ClientWorker implements Closeable {
return ct;
case HttpURLConnection.HTTP_CONFLICT: {
LOGGER.error(
"[{}] [sub-server-error] get server config being modified concurrently, dataId={}, group={}, "
+ "tenant={}", agent.getName(), dataId, group, tenant);
"[{}] [sub-server-error] get server config being modified concurrently, dataId={}, group={}, "
+ "tenant={}", agent.getName(), dataId, group, tenant);
throw new NacosException(NacosException.CONFLICT,
"data being modified, dataId=" + dataId + ",group=" + group + ",tenant=" + tenant);
"data being modified, dataId=" + dataId + ",group=" + group + ",tenant=" + tenant);
}
case HttpURLConnection.HTTP_FORBIDDEN: {
LOGGER.error("[{}] [sub-server-error] no right, dataId={}, group={}, tenant={}", agent.getName(), dataId,
group, tenant);
LOGGER.error("[{}] [sub-server-error] no right, dataId={}, group={}, tenant={}", agent.getName(),
dataId, group, tenant);
throw new NacosException(result.code, result.content);
}
default: {
LOGGER.error("[{}] [sub-server-error] dataId={}, group={}, tenant={}, code={}", agent.getName(), dataId,
group, tenant, result.code);
LOGGER.error("[{}] [sub-server-error] dataId={}, group={}, tenant={}, code={}", agent.getName(),
dataId, group, tenant, result.code);
throw new NacosException(result.code,
"http error, code=" + result.code + ",dataId=" + dataId + ",group=" + group + ",tenant=" + tenant);
"http error, code=" + result.code + ",dataId=" + dataId + ",group=" + group + ",tenant="
+ tenant);
}
}
}
private void checkLocalConfig(CacheData cacheData) {
final String dataId = cacheData.dataId;
final String group = cacheData.group;
final String tenant = cacheData.tenant;
File path = LocalConfigInfoProcessor.getFailoverFile(agent.getName(), dataId, group, tenant);
if (!cacheData.isUseLocalConfigInfo() && path.exists()) {
String content = LocalConfigInfoProcessor.getFailover(agent.getName(), dataId, group, tenant);
String md5 = MD5Utils.md5Hex(content, Constants.ENCODE);
final String md5 = MD5Utils.md5Hex(content, Constants.ENCODE);
cacheData.setUseLocalConfigInfo(true);
cacheData.setLocalConfigInfoVersion(path.lastModified());
cacheData.setContent(content);
LOGGER.warn("[{}] [failover-change] failover file created. dataId={}, group={}, tenant={}, md5={}, content={}",
agent.getName(), dataId, group, tenant, md5, ContentUtils.truncateContent(content));
LOGGER.warn(
"[{}] [failover-change] failover file created. dataId={}, group={}, tenant={}, md5={}, content={}",
agent.getName(), dataId, group, tenant, md5, ContentUtils.truncateContent(content));
return;
}
// If use local config info, then it doesn't notify business listener and notify after getting from server.
if (cacheData.isUseLocalConfigInfo() && !path.exists()) {
cacheData.setUseLocalConfigInfo(false);
LOGGER.warn("[{}] [failover-change] failover file deleted. dataId={}, group={}, tenant={}", agent.getName(),
dataId, group, tenant);
dataId, group, tenant);
return;
}
// When it changed.
if (cacheData.isUseLocalConfigInfo() && path.exists()
&& cacheData.getLocalConfigInfoVersion() != path.lastModified()) {
if (cacheData.isUseLocalConfigInfo() && path.exists() && cacheData.getLocalConfigInfoVersion() != path
.lastModified()) {
String content = LocalConfigInfoProcessor.getFailover(agent.getName(), dataId, group, tenant);
String md5 = MD5Utils.md5Hex(content, Constants.ENCODE);
final String md5 = MD5Utils.md5Hex(content, Constants.ENCODE);
cacheData.setUseLocalConfigInfo(true);
cacheData.setLocalConfigInfoVersion(path.lastModified());
cacheData.setContent(content);
LOGGER.warn("[{}] [failover-change] failover file changed. dataId={}, group={}, tenant={}, md5={}, content={}",
agent.getName(), dataId, group, tenant, md5, ContentUtils.truncateContent(content));
LOGGER.warn(
"[{}] [failover-change] failover file changed. dataId={}, group={}, tenant={}, md5={}, content={}",
agent.getName(), dataId, group, tenant, md5, ContentUtils.truncateContent(content));
}
}
private String null2defaultGroup(String group) {
return (null == group) ? Constants.DEFAULT_GROUP : group.trim();
}
/**
* Check config info.
*/
public void checkConfigInfo() {
// Dispatch taskes.
int listenerSize = cacheMap.get().size();
@ -336,17 +398,17 @@ public class ClientWorker implements Closeable {
currentLongingTaskCount = longingTaskCount;
}
}
/**
* Fetch the dataId list from server.
*
* @param cacheDatas CacheDatas for config infomations.
* @param cacheDatas CacheDatas for config infomations.
* @param inInitializingCacheList initial cache lists.
* @return String include dataId and group (ps: it maybe null).
*
* @throws IOException Exception.
*/
List<String> checkUpdateDataIds(List<CacheData> cacheDatas, List<String> inInitializingCacheList) throws IOException {
List<String> checkUpdateDataIds(List<CacheData> cacheDatas, List<String> inInitializingCacheList)
throws IOException {
StringBuilder sb = new StringBuilder();
for (CacheData cacheData : cacheDatas) {
if (!cacheData.isUseLocalConfigInfo()) {
@ -361,52 +423,51 @@ public class ClientWorker implements Closeable {
if (cacheData.isInitializing()) {
// It updates when cacheData occours in cacheMap by first time.
inInitializingCacheList
.add(GroupKey.getKeyTenant(cacheData.dataId, cacheData.group, cacheData.tenant));
.add(GroupKey.getKeyTenant(cacheData.dataId, cacheData.group, cacheData.tenant));
}
}
}
boolean isInitializingCacheList = !inInitializingCacheList.isEmpty();
return checkUpdateConfigStr(sb.toString(), isInitializingCacheList);
}
/**
* Fetch the updated dataId list from server.
*
*
* @param probeUpdateString updated attribute string value.
* @param probeUpdateString updated attribute string value.
* @param isInitializingCacheList initial cache lists.
* @return The updated dataId list(ps: it maybe null).
* @throws IOException Exception.
*/
List<String> checkUpdateConfigStr(String probeUpdateString, boolean isInitializingCacheList) throws IOException {
List<String> params = new ArrayList<String>(2);
params.add(Constants.PROBE_MODIFY_REQUEST);
params.add(probeUpdateString);
List<String> headers = new ArrayList<String>(2);
headers.add("Long-Pulling-Timeout");
headers.add("" + timeout);
// told server do not hang me up if new initializing cacheData added in
if (isInitializingCacheList) {
headers.add("Long-Pulling-Timeout-No-Hangup");
headers.add("true");
}
if (StringUtils.isBlank(probeUpdateString)) {
return Collections.emptyList();
}
try {
// In order to prevent the server from handling the delay of the client's long task,
// increase the client's read timeout to avoid this problem.
long readTimeoutMs = timeout + (long) Math.round(timeout >> 1);
HttpResult result = agent.httpPost(Constants.CONFIG_CONTROLLER_PATH + "/listener", headers, params,
agent.getEncode(), readTimeoutMs);
HttpResult result = agent
.httpPost(Constants.CONFIG_CONTROLLER_PATH + "/listener", headers, params, agent.getEncode(),
readTimeoutMs);
if (HttpURLConnection.HTTP_OK == result.code) {
setHealthServer(true);
return parseUpdateDataIdResponse(result.content);
@ -421,7 +482,7 @@ public class ClientWorker implements Closeable {
}
return Collections.emptyList();
}
/**
* Get the groupKey list from the http response.
*
@ -432,15 +493,15 @@ public class ClientWorker implements Closeable {
if (StringUtils.isBlank(response)) {
return Collections.emptyList();
}
try {
response = URLDecoder.decode(response, "UTF-8");
} catch (Exception e) {
LOGGER.error("[" + agent.getName() + "] [polling-resp] decode modifiedDataIdsString error", e);
}
List<String> updateList = new LinkedList<String>();
for (String dataIdAndGroup : response.split(LINE_SEPARATOR)) {
if (!StringUtils.isBlank(dataIdAndGroup)) {
String[] keyArr = dataIdAndGroup.split(WORD_SEPARATOR);
@ -448,29 +509,32 @@ public class ClientWorker implements Closeable {
String group = keyArr[1];
if (keyArr.length == 2) {
updateList.add(GroupKey.getKey(dataId, group));
LOGGER.info("[{}] [polling-resp] config changed. dataId={}, group={}", agent.getName(), dataId, group);
LOGGER.info("[{}] [polling-resp] config changed. dataId={}, group={}", agent.getName(), dataId,
group);
} else if (keyArr.length == 3) {
String tenant = keyArr[2];
updateList.add(GroupKey.getKeyTenant(dataId, group, tenant));
LOGGER.info("[{}] [polling-resp] config changed. dataId={}, group={}, tenant={}", agent.getName(),
dataId, group, tenant);
dataId, group, tenant);
} else {
LOGGER.error("[{}] [polling-resp] invalid dataIdAndGroup error {}", agent.getName(), dataIdAndGroup);
LOGGER.error("[{}] [polling-resp] invalid dataIdAndGroup error {}", agent.getName(),
dataIdAndGroup);
}
}
}
return updateList;
}
@SuppressWarnings("PMD.ThreadPoolCreationRule")
public ClientWorker(final HttpAgent agent, final ConfigFilterChainManager configFilterChainManager, final Properties properties) {
public ClientWorker(final HttpAgent agent, final ConfigFilterChainManager configFilterChainManager,
final Properties properties) {
this.agent = agent;
this.configFilterChainManager = configFilterChainManager;
// Initialize the timeout parameter
init(properties);
this.executor = Executors.newScheduledThreadPool(1, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
@ -480,17 +544,18 @@ public class ClientWorker implements Closeable {
return t;
}
});
this.executorService = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("com.alibaba.nacos.client.Worker.longPolling." + agent.getName());
t.setDaemon(true);
return t;
}
});
this.executorService = Executors
.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("com.alibaba.nacos.client.Worker.longPolling." + agent.getName());
t.setDaemon(true);
return t;
}
});
this.executor.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
@ -502,17 +567,19 @@ public class ClientWorker implements Closeable {
}
}, 1L, 10L, TimeUnit.MILLISECONDS);
}
private void init(Properties properties) {
timeout = Math.max(ConvertUtils.toInt(properties.getProperty(PropertyKeyConst.CONFIG_LONG_POLL_TIMEOUT),
Constants.CONFIG_LONG_POLL_TIMEOUT), Constants.MIN_CONFIG_LONG_POLL_TIMEOUT);
taskPenaltyTime = ConvertUtils.toInt(properties.getProperty(PropertyKeyConst.CONFIG_RETRY_TIME), Constants.CONFIG_RETRY_TIME);
this.enableRemoteSyncConfig = Boolean.parseBoolean(properties.getProperty(PropertyKeyConst.ENABLE_REMOTE_SYNC_CONFIG));
Constants.CONFIG_LONG_POLL_TIMEOUT), Constants.MIN_CONFIG_LONG_POLL_TIMEOUT);
taskPenaltyTime = ConvertUtils
.toInt(properties.getProperty(PropertyKeyConst.CONFIG_RETRY_TIME), Constants.CONFIG_RETRY_TIME);
this.enableRemoteSyncConfig = Boolean
.parseBoolean(properties.getProperty(PropertyKeyConst.ENABLE_REMOTE_SYNC_CONFIG));
}
@Override
public void shutdown() throws NacosException {
String className = this.getClass().getName();
@ -521,17 +588,18 @@ public class ClientWorker implements Closeable {
ThreadUtils.shutdownThreadPool(executor, LOGGER);
LOGGER.info("{} do shutdown stop", className);
}
class LongPollingRunnable implements Runnable {
private int taskId;
private final int taskId;
public LongPollingRunnable(int taskId) {
this.taskId = taskId;
}
@Override
public void run() {
List<CacheData> cacheDatas = new ArrayList<CacheData>();
List<String> inInitializingCacheList = new ArrayList<String>();
try {
@ -549,14 +617,13 @@ public class ClientWorker implements Closeable {
}
}
}
// check server config
List<String> changedGroupKeys = checkUpdateDataIds(cacheDatas, inInitializingCacheList);
if (!CollectionUtils.isEmpty(changedGroupKeys)) {
LOGGER.info("get changedGroupKeys:" + changedGroupKeys);
}
for (String groupKey : changedGroupKeys) {
String[] key = GroupKey.parseKey(groupKey);
String dataId = key[0];
@ -573,57 +640,64 @@ public class ClientWorker implements Closeable {
cache.setType(ct[1]);
}
LOGGER.info("[{}] [data-received] dataId={}, group={}, tenant={}, md5={}, content={}, type={}",
agent.getName(), dataId, group, tenant, cache.getMd5(),
ContentUtils.truncateContent(ct[0]), ct[1]);
agent.getName(), dataId, group, tenant, cache.getMd5(),
ContentUtils.truncateContent(ct[0]), ct[1]);
} catch (NacosException ioe) {
String message = String.format(
"[%s] [get-update] get changed config exception. dataId=%s, group=%s, tenant=%s",
agent.getName(), dataId, group, tenant);
String message = String
.format("[%s] [get-update] get changed config exception. dataId=%s, group=%s, tenant=%s",
agent.getName(), dataId, group, tenant);
LOGGER.error(message, ioe);
}
}
for (CacheData cacheData : cacheDatas) {
if (!cacheData.isInitializing() || inInitializingCacheList
.contains(GroupKey.getKeyTenant(cacheData.dataId, cacheData.group, cacheData.tenant))) {
.contains(GroupKey.getKeyTenant(cacheData.dataId, cacheData.group, cacheData.tenant))) {
cacheData.checkListenerMd5();
cacheData.setInitializing(false);
}
}
inInitializingCacheList.clear();
executorService.execute(this);
} catch (Throwable e) {
// If the rotation training task is abnormal, the next execution time of the task will be punished
LOGGER.error("longPolling error : ", e);
executorService.schedule(this, taskPenaltyTime, TimeUnit.MILLISECONDS);
}
}
}
public boolean isHealthServer() {
return isHealthServer;
}
private void setHealthServer(boolean isHealthServer) {
this.isHealthServer = isHealthServer;
}
final ScheduledExecutorService executor;
final ScheduledExecutorService executorService;
/**
* groupKey -> cacheData
* groupKey -> cacheData.
*/
private final AtomicReference<Map<String, CacheData>> cacheMap = new AtomicReference<Map<String, CacheData>>(
new HashMap<String, CacheData>());
new HashMap<String, CacheData>());
private final HttpAgent agent;
private final ConfigFilterChainManager configFilterChainManager;
private boolean isHealthServer = true;
private long timeout;
private double currentLongingTaskCount = 0;
private int taskPenaltyTime;
private boolean enableRemoteSyncConfig = false;
}

View File

@ -13,55 +13,67 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.impl;
import com.alibaba.nacos.api.config.listener.ConfigChangeParser;
import java.io.IOException;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ServiceLoader;
import java.util.Map;
import java.util.Iterator;
import java.util.ServiceLoader;
/**
* ConfigChangeHandler
* ConfigChangeHandler.
*
* @author rushsky518
*/
public class ConfigChangeHandler {
private static class ConfigChangeHandlerHolder {
private final static ConfigChangeHandler INSTANCE = new ConfigChangeHandler();
private static final ConfigChangeHandler INSTANCE = new ConfigChangeHandler();
}
private ConfigChangeHandler() {
this.parserList = new LinkedList<ConfigChangeParser>();
ServiceLoader<ConfigChangeParser> loader = ServiceLoader.load(ConfigChangeParser.class);
Iterator<ConfigChangeParser> itr = loader.iterator();
while (itr.hasNext()) {
this.parserList.add(itr.next());
}
this.parserList.add(new PropertiesChangeParser());
this.parserList.add(new YmlChangeParser());
}
public static ConfigChangeHandler getInstance() {
return ConfigChangeHandlerHolder.INSTANCE;
}
/**
* Parse changed data.
*
* @param oldContent old data
* @param newContent new data
* @param type data type
* @return change data map
* @throws IOException io exception
*/
public Map parseChangeData(String oldContent, String newContent, String type) throws IOException {
for (ConfigChangeParser changeParser: this.parserList) {
for (ConfigChangeParser changeParser : this.parserList) {
if (changeParser.isResponsibleFor(type)) {
return changeParser.doParse(oldContent, newContent, type);
}
}
return Collections.emptyMap();
}
private List<ConfigChangeParser> parserList;
private final List<ConfigChangeParser> parserList;
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.impl;
import com.alibaba.nacos.client.utils.LogUtils;
@ -30,26 +31,26 @@ import java.util.concurrent.CopyOnWriteArrayList;
* @author Nacos
*/
public class EventDispatcher {
private static final Logger LOGGER = LogUtils.logger(EventDispatcher.class);
/**
* 添加事件监听器
* 添加事件监听器.
*/
static public void addEventListener(AbstractEventListener listener) {
public static void addEventListener(AbstractEventListener listener) {
for (Class<? extends AbstractEvent> type : listener.interest()) {
getListenerList(type).addIfAbsent(listener);
}
}
/**
* 发布事件首先发布该事件暗示的其他事件最后通知所有对应的监听器
* 发布事件首先发布该事件暗示的其他事件最后通知所有对应的监听器.
*/
static public void fireEvent(AbstractEvent abstractEvent) {
public static void fireEvent(AbstractEvent abstractEvent) {
if (null == abstractEvent) {
return;
}
// 发布该事件暗示的其他事件
for (AbstractEvent implyEvent : abstractEvent.implyEvents()) {
try {
@ -61,7 +62,7 @@ public class EventDispatcher {
LOGGER.warn(e.toString(), e);
}
}
for (AbstractEventListener listener : getListenerList(abstractEvent.getClass())) {
try {
listener.onEvent(abstractEvent);
@ -70,9 +71,9 @@ public class EventDispatcher {
}
}
}
static synchronized CopyOnWriteArrayList<AbstractEventListener> getListenerList(
Class<? extends AbstractEvent> eventType) {
Class<? extends AbstractEvent> eventType) {
CopyOnWriteArrayList<AbstractEventListener> listeners = LISTENER_MAP.get(eventType);
if (null == listeners) {
listeners = new CopyOnWriteArrayList<AbstractEventListener>();
@ -80,54 +81,48 @@ public class EventDispatcher {
}
return listeners;
}
// ========================
static final Map<Class<? extends AbstractEvent>, CopyOnWriteArrayList<AbstractEventListener>> LISTENER_MAP
= new HashMap<Class<? extends AbstractEvent>, CopyOnWriteArrayList<AbstractEventListener>>();
// ========================
@SuppressWarnings("checkstyle:linelength")
static final Map<Class<? extends AbstractEvent>, CopyOnWriteArrayList<AbstractEventListener>> LISTENER_MAP = new HashMap<Class<? extends AbstractEvent>, CopyOnWriteArrayList<AbstractEventListener>>();
/**
* Client事件
* Client事件.
*/
static public abstract class AbstractEvent {
public abstract static class AbstractEvent {
@SuppressWarnings("unchecked")
protected List<AbstractEvent> implyEvents() {
return Collections.EMPTY_LIST;
}
}
/**
* 事件监听器
* 事件监听器.
*/
static public abstract class AbstractEventListener {
public abstract static class AbstractEventListener {
public AbstractEventListener() {
/**
* 自动注册给EventDispatcher
*/
EventDispatcher.addEventListener(this);
}
/**
* 感兴趣的事件列表
* 感兴趣的事件列表.
*
* @return event list
*/
abstract public List<Class<? extends AbstractEvent>> interest();
public abstract List<Class<? extends AbstractEvent>> interest();
/**
* 处理事件
* 处理事件.
*
* @param abstractEvent event to do
*/
abstract public void onEvent(AbstractEvent abstractEvent);
public abstract void onEvent(AbstractEvent abstractEvent);
}
/**
* serverList has changed
* serverList has changed.
*/
static public class ServerlistChangeEvent extends AbstractEvent {
public static class ServerlistChangeEvent extends AbstractEvent {
}
}

View File

@ -13,14 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.impl;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.common.utils.MD5Utils;
import com.alibaba.nacos.client.utils.ParamUtil;
import com.alibaba.nacos.common.constant.HttpHeaderConsts;
import com.alibaba.nacos.common.utils.IoUtils;
import com.alibaba.nacos.common.utils.MD5Utils;
import com.alibaba.nacos.common.utils.UuidUtils;
import com.alibaba.nacos.common.utils.VersionUtils;
@ -29,27 +30,42 @@ import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Http tool
* Http tool.
*
* @author Nacos
*/
public class HttpSimpleClient {
static public HttpResult httpGet(String url, List<String> headers, List<String> paramValues,
String encoding, long readTimeoutMs, boolean isSSL) throws IOException {
/**
* Get method.
*
* @param url url
* @param headers headers
* @param paramValues paramValues
* @param encoding encoding
* @param readTimeoutMs readTimeoutMs
* @param isSsl isSsl
* @return result
* @throws IOException io exception
*/
public static HttpResult httpGet(String url, List<String> headers, List<String> paramValues, String encoding,
long readTimeoutMs, boolean isSsl) throws IOException {
String encodedContent = encodingParams(paramValues, encoding);
url += (null == encodedContent) ? "" : ("?" + encodedContent);
if (Limiter.isLimit(MD5Utils.md5Hex(
new StringBuilder(url).append(encodedContent).toString(), Constants.ENCODE))) {
if (Limiter
.isLimit(MD5Utils.md5Hex(new StringBuilder(url).append(encodedContent).toString(), Constants.ENCODE))) {
return new HttpResult(NacosException.CLIENT_OVER_THRESHOLD,
"More than client-side current limit threshold");
"More than client-side current limit threshold");
}
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestMethod("GET");
@ -57,12 +73,12 @@ public class HttpSimpleClient {
conn.setReadTimeout((int) readTimeoutMs);
List<String> newHeaders = getHeaders(url, headers, paramValues);
setHeaders(conn, newHeaders, encoding);
conn.connect();
int respCode = conn.getResponseCode();
String resp = null;
if (HttpURLConnection.HTTP_OK == respCode) {
resp = IoUtils.toString(conn.getInputStream(), encoding);
} else {
@ -73,35 +89,35 @@ public class HttpSimpleClient {
IoUtils.closeQuietly(conn);
}
}
/**
* 发送GET请求
* 发送GET请求.
*/
static public HttpResult httpGet(String url, List<String> headers, List<String> paramValues, String encoding,
long readTimeoutMs) throws IOException {
public static HttpResult httpGet(String url, List<String> headers, List<String> paramValues, String encoding,
long readTimeoutMs) throws IOException {
return httpGet(url, headers, paramValues, encoding, readTimeoutMs, false);
}
/**
* 发送POST请求
* 发送POST请求.
*
* @param url
* @param url url
* @param headers 请求Header可以为null
* @param paramValues 参数可以为null
* @param encoding URL编码使用的字符集
* @param readTimeoutMs 响应超时
* @param isSSL 是否https
* @return
* @throws IOException
* @param isSsl 是否https
* @return result
* @throws IOException io exception
*/
static public HttpResult httpPost(String url, List<String> headers, List<String> paramValues,
String encoding, long readTimeoutMs, boolean isSSL) throws IOException {
public static HttpResult httpPost(String url, List<String> headers, List<String> paramValues, String encoding,
long readTimeoutMs, boolean isSsl) throws IOException {
String encodedContent = encodingParams(paramValues, encoding);
encodedContent = (null == encodedContent) ? "" : encodedContent;
if (Limiter.isLimit(MD5Utils.md5Hex(
new StringBuilder(url).append(encodedContent).toString(), Constants.ENCODE))) {
if (Limiter
.isLimit(MD5Utils.md5Hex(new StringBuilder(url).append(encodedContent).toString(), Constants.ENCODE))) {
return new HttpResult(NacosException.CLIENT_OVER_THRESHOLD,
"More than client-side current limit threshold");
"More than client-side current limit threshold");
}
HttpURLConnection conn = null;
try {
@ -113,12 +129,12 @@ public class HttpSimpleClient {
conn.setDoInput(true);
List<String> newHeaders = getHeaders(url, headers, paramValues);
setHeaders(conn, newHeaders, encoding);
conn.getOutputStream().write(encodedContent.getBytes(encoding));
int respCode = conn.getResponseCode();
String resp = null;
if (HttpURLConnection.HTTP_OK == respCode) {
resp = IoUtils.toString(conn.getInputStream(), encoding);
} else {
@ -129,35 +145,47 @@ public class HttpSimpleClient {
IoUtils.closeQuietly(conn);
}
}
/**
* 发送POST请求
* 发送POST请求.
*
* @param url
* @param url url
* @param headers 请求Header可以为null
* @param paramValues 参数可以为null
* @param encoding URL编码使用的字符集
* @param readTimeoutMs 响应超时
* @return
* @throws IOException
* @return result
* @throws IOException io exception
*/
static public HttpResult httpPost(String url, List<String> headers, List<String> paramValues, String encoding,
long readTimeoutMs) throws IOException {
public static HttpResult httpPost(String url, List<String> headers, List<String> paramValues, String encoding,
long readTimeoutMs) throws IOException {
return httpPost(url, headers, paramValues, encoding, readTimeoutMs, false);
}
static public HttpResult httpDelete(String url, List<String> headers, List<String> paramValues,
String encoding, long readTimeoutMs, boolean isSSL) throws IOException {
/**
* Delete method.
*
* @param url url
* @param headers 请求Header可以为null
* @param paramValues 参数可以为null
* @param encoding URL编码使用的字符集
* @param readTimeoutMs 响应超时
* @param isSsl 是否https
* @return result
* @throws IOException io exception
*/
public static HttpResult httpDelete(String url, List<String> headers, List<String> paramValues, String encoding,
long readTimeoutMs, boolean isSsl) throws IOException {
String encodedContent = encodingParams(paramValues, encoding);
url += (null == encodedContent) ? "" : ("?" + encodedContent);
if (Limiter.isLimit(MD5Utils.md5Hex(
new StringBuilder(url).append(encodedContent).toString(), Constants.ENCODE))) {
if (Limiter
.isLimit(MD5Utils.md5Hex(new StringBuilder(url).append(encodedContent).toString(), Constants.ENCODE))) {
return new HttpResult(NacosException.CLIENT_OVER_THRESHOLD,
"More than client-side current limit threshold");
"More than client-side current limit threshold");
}
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestMethod("DELETE");
@ -165,12 +193,12 @@ public class HttpSimpleClient {
conn.setReadTimeout((int) readTimeoutMs);
List<String> newHeaders = getHeaders(url, headers, paramValues);
setHeaders(conn, newHeaders, encoding);
conn.connect();
int respCode = conn.getResponseCode();
String resp = null;
if (HttpURLConnection.HTTP_OK == respCode) {
resp = IoUtils.toString(conn.getInputStream(), encoding);
} else {
@ -181,13 +209,24 @@ public class HttpSimpleClient {
IoUtils.closeQuietly(conn);
}
}
static public HttpResult httpDelete(String url, List<String> headers, List<String> paramValues, String encoding,
long readTimeoutMs) throws IOException {
/**
* Delete method.
*
* @param url url
* @param headers 请求Header可以为null
* @param paramValues 参数可以为null
* @param encoding URL编码使用的字符集
* @param readTimeoutMs 响应超时
* @return result
* @throws IOException io exception
*/
public static HttpResult httpDelete(String url, List<String> headers, List<String> paramValues, String encoding,
long readTimeoutMs) throws IOException {
return httpGet(url, headers, paramValues, encoding, readTimeoutMs, false);
}
static private void setHeaders(HttpURLConnection conn, List<String> headers, String encoding) {
private static void setHeaders(HttpURLConnection conn, List<String> headers, String encoding) {
if (null != headers) {
for (Iterator<String> iter = headers.iterator(); iter.hasNext(); ) {
conn.addRequestProperty(iter.next(), iter.next());
@ -195,17 +234,17 @@ public class HttpSimpleClient {
}
conn.addRequestProperty(HttpHeaderConsts.CLIENT_VERSION_HEADER, VersionUtils.version);
conn.addRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + encoding);
String ts = String.valueOf(System.currentTimeMillis());
String token = MD5Utils.md5Hex(ts + ParamUtil.getAppKey(), Constants.ENCODE);
conn.addRequestProperty(Constants.CLIENT_APPNAME_HEADER, ParamUtil.getAppName());
conn.addRequestProperty(Constants.CLIENT_REQUEST_TS_HEADER, ts);
conn.addRequestProperty(Constants.CLIENT_REQUEST_TOKEN_HEADER, token);
}
private static List<String> getHeaders(String url, List<String> headers, List<String> paramValues)
throws IOException {
throws IOException {
List<String> newHeaders = new ArrayList<String>();
newHeaders.add("exConfigInfo");
newHeaders.add("true");
@ -216,14 +255,14 @@ public class HttpSimpleClient {
}
return newHeaders;
}
static private String encodingParams(List<String> paramValues, String encoding)
throws UnsupportedEncodingException {
private static String encodingParams(List<String> paramValues, String encoding)
throws UnsupportedEncodingException {
StringBuilder sb = new StringBuilder();
if (null == paramValues) {
return null;
}
for (Iterator<String> iter = paramValues.iterator(); iter.hasNext(); ) {
sb.append(iter.next()).append("=");
sb.append(URLEncoder.encode(iter.next(), encoding));
@ -233,29 +272,31 @@ public class HttpSimpleClient {
}
return sb.toString();
}
static public class HttpResult {
final public int code;
final public Map<String, List<String>> headers;
final public String content;
public static class HttpResult {
public final int code;
public final Map<String, List<String>> headers;
public final String content;
public HttpResult(int code, String content) {
this.code = code;
this.headers = null;
this.content = content;
}
public HttpResult(int code, Map<String, List<String>> headers, String content) {
this.code = code;
this.headers = headers;
this.content = content;
}
@Override
public String toString() {
return "HttpResult{" + "code=" + code + ", headers=" + headers + ", content='"
+ content + '\'' + '}';
return "HttpResult{" + "code=" + code + ", headers=" + headers + ", content='" + content + '\'' + '}';
}
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.impl;
import com.alibaba.nacos.client.utils.LogUtils;
@ -26,40 +27,46 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
/**
* Limiter
* Limiter.
*
* @author Nacos
*/
public class Limiter {
private static final Logger LOGGER = LogUtils.logger(Limiter.class);
private static final int CAPACITY_SIZE = 1000;
private static final int LIMIT_TIME = 1000;
private static Cache<String, RateLimiter> cache = CacheBuilder.newBuilder()
.initialCapacity(CAPACITY_SIZE).expireAfterAccess(1, TimeUnit.MINUTES)
.build();
private static final Cache<String, RateLimiter> CACHE = CacheBuilder.newBuilder().initialCapacity(CAPACITY_SIZE)
.expireAfterAccess(1, TimeUnit.MINUTES).build();
/**
* qps 5
* qps 5.
*/
private static double limit = 5;
static {
try {
String limitTimeStr = System
.getProperty("limitTime", String.valueOf(limit));
String limitTimeStr = System.getProperty("limitTime", String.valueOf(limit));
limit = Double.parseDouble(limitTimeStr);
LOGGER.info("limitTime:{}", limit);
} catch (Exception e) {
LOGGER.error("init limitTime fail", e);
}
}
/**
* Judge whether access key is limited.
*
* @param accessKeyID access key
* @return true if is limited, otherwise false
*/
public static boolean isLimit(String accessKeyID) {
RateLimiter rateLimiter = null;
try {
rateLimiter = cache.get(accessKeyID, new Callable<RateLimiter>() {
rateLimiter = CACHE.get(accessKeyID, new Callable<RateLimiter>() {
@Override
public RateLimiter call() throws Exception {
return RateLimiter.create(limit);
@ -74,5 +81,5 @@ public class Limiter {
}
return false;
}
}

View File

@ -13,11 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.impl;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.client.config.utils.ConcurrentDiskUtil;
import com.alibaba.nacos.client.config.utils.JVMUtil;
import com.alibaba.nacos.client.config.utils.JvmUtil;
import com.alibaba.nacos.client.config.utils.SnapShotSwitch;
import com.alibaba.nacos.client.utils.LogUtils;
import com.alibaba.nacos.common.utils.IoUtils;
@ -30,20 +31,20 @@ import java.io.IOException;
import java.io.InputStream;
/**
* Local Disaster Recovery Directory Tool
* Local Disaster Recovery Directory Tool.
*
* @author Nacos
*/
public class LocalConfigInfoProcessor {
private static final Logger LOGGER = LogUtils.logger(LocalConfigInfoProcessor.class);
static public String getFailover(String serverName, String dataId, String group, String tenant) {
public static String getFailover(String serverName, String dataId, String group, String tenant) {
File localPath = getFailoverFile(serverName, dataId, group, tenant);
if (!localPath.exists() || !localPath.isFile()) {
return null;
}
try {
return readFile(localPath);
} catch (IOException ioe) {
@ -51,11 +52,11 @@ public class LocalConfigInfoProcessor {
return null;
}
}
/**
* 获取本地缓存文件内容NULL表示没有本地文件或抛出异常
* 获取本地缓存文件内容NULL表示没有本地文件或抛出异常.
*/
static public String getSnapshot(String name, String dataId, String group, String tenant) {
public static String getSnapshot(String name, String dataId, String group, String tenant) {
if (!SnapShotSwitch.getIsSnapShot()) {
return null;
}
@ -63,7 +64,7 @@ public class LocalConfigInfoProcessor {
if (!file.exists() || !file.isFile()) {
return null;
}
try {
return readFile(file);
} catch (IOException ioe) {
@ -71,13 +72,13 @@ public class LocalConfigInfoProcessor {
return null;
}
}
static private String readFile(File file) throws IOException {
private static String readFile(File file) throws IOException {
if (!file.exists() || !file.isFile()) {
return null;
}
if (JVMUtil.isMultiInstance()) {
if (JvmUtil.isMultiInstance()) {
return ConcurrentDiskUtil.getFileContent(file, Constants.ENCODE);
} else {
InputStream is = null;
@ -89,13 +90,22 @@ public class LocalConfigInfoProcessor {
if (null != is) {
is.close();
}
} catch (IOException ioe) {
} catch (IOException ignored) {
}
}
}
}
static public void saveSnapshot(String envName, String dataId, String group, String tenant, String config) {
/**
* Save snapshot.
*
* @param envName env name
* @param dataId data id
* @param group group
* @param tenant tenant
* @param config config
*/
public static void saveSnapshot(String envName, String dataId, String group, String tenant, String config) {
if (!SnapShotSwitch.getIsSnapShot()) {
return;
}
@ -115,10 +125,9 @@ public class LocalConfigInfoProcessor {
LOGGER.error("[{}] save snapshot error", envName);
}
}
if (JVMUtil.isMultiInstance()) {
ConcurrentDiskUtil.writeFileContent(file, config,
Constants.ENCODE);
if (JvmUtil.isMultiInstance()) {
ConcurrentDiskUtil.writeFileContent(file, config, Constants.ENCODE);
} else {
IoUtils.writeStringToFile(file, config, Constants.ENCODE);
}
@ -127,11 +136,11 @@ public class LocalConfigInfoProcessor {
}
}
}
/**
* 清除snapshot目录下所有缓存文件
* 清除snapshot目录下所有缓存文件.
*/
static public void cleanAllSnapshot() {
public static void cleanAllSnapshot() {
try {
File rootFile = new File(LOCAL_SNAPSHOT_PATH);
File[] files = rootFile.listFiles();
@ -147,8 +156,13 @@ public class LocalConfigInfoProcessor {
LOGGER.error("clean all snapshot error, " + ioe.toString(), ioe);
}
}
static public void cleanEnvSnapshot(String envName) {
/**
* Clean snapshot.
*
* @param envName env name
*/
public static void cleanEnvSnapshot(String envName) {
File tmp = new File(LOCAL_SNAPSHOT_PATH, envName + "_nacos");
tmp = new File(tmp, "snapshot");
try {
@ -159,7 +173,7 @@ public class LocalConfigInfoProcessor {
e.printStackTrace();
}
}
static File getFailoverFile(String serverName, String dataId, String group, String tenant) {
File tmp = new File(LOCAL_SNAPSHOT_PATH, serverName + "_nacos");
tmp = new File(tmp, "data");
@ -171,7 +185,7 @@ public class LocalConfigInfoProcessor {
}
return new File(new File(tmp, group), dataId);
}
static File getSnapshotFile(String envName, String dataId, String group, String tenant) {
File tmp = new File(LOCAL_SNAPSHOT_PATH, envName + "_nacos");
if (StringUtils.isBlank(tenant)) {
@ -180,19 +194,22 @@ public class LocalConfigInfoProcessor {
tmp = new File(tmp, "snapshot-tenant");
tmp = new File(tmp, tenant);
}
return new File(new File(tmp, group), dataId);
}
public static final String LOCAL_FILEROOT_PATH;
public static final String LOCAL_SNAPSHOT_PATH;
static {
LOCAL_FILEROOT_PATH = System.getProperty("JM.LOG.PATH", System.getProperty("user.home")) + File.separator
+ "nacos" + File.separator + "config";
LOCAL_SNAPSHOT_PATH = System.getProperty("JM.SNAPSHOT.PATH", System.getProperty("user.home")) + File.separator
+ "nacos" + File.separator + "config";
LOCAL_FILEROOT_PATH =
System.getProperty("JM.LOG.PATH", System.getProperty("user.home")) + File.separator + "nacos"
+ File.separator + "config";
LOCAL_SNAPSHOT_PATH =
System.getProperty("JM.SNAPSHOT.PATH", System.getProperty("user.home")) + File.separator + "nacos"
+ File.separator + "config";
LOGGER.info("LOCAL_SNAPSHOT_PATH:{}", LOCAL_SNAPSHOT_PATH);
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.impl;
import com.alibaba.nacos.api.config.ConfigChangeItem;
@ -24,27 +25,28 @@ import java.util.Map;
import java.util.Properties;
/**
* PropertiesChangeParser
* PropertiesChangeParser.
*
* @author rushsky518
*/
public class PropertiesChangeParser extends AbstractConfigChangeParser {
public PropertiesChangeParser() {
super("properties");
}
@Override
public Map<String, ConfigChangeItem> doParse(String oldContent, String newContent, String type) throws IOException {
Properties oldProps = new Properties();
Properties newProps = new Properties();
if (StringUtils.isNotBlank(oldContent)) {
oldProps.load(new StringReader(oldContent));
}
if (StringUtils.isNotBlank(newContent)) {
newProps.load(new StringReader(newContent));
}
return filterChangeData(oldProps, newProps);
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.impl;
import com.alibaba.nacos.api.PropertyKeyConst;
@ -33,30 +34,32 @@ import org.slf4j.Logger;
import java.io.IOException;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.util.List;
import java.util.ArrayList;
import java.util.Properties;
import java.util.Iterator;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
/**
* Serverlist Manager
* Serverlist Manager.
*
* @author Nacos
*/
public class ServerListManager implements Closeable {
private static final Logger LOGGER = LogUtils.logger(ServerListManager.class);
private static final String HTTPS = "https://";
private static final String HTTP = "http://";
private ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
private final ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
@ -65,17 +68,17 @@ public class ServerListManager implements Closeable {
return t;
}
});
public ServerListManager() {
this.isFixed = false;
this.isStarted = false;
this.name = DEFAULT_NAME;
}
public ServerListManager(List<String> fixed) {
this(fixed, null);
}
public ServerListManager(List<String> fixed, String namespace) {
this.isFixed = true;
this.isStarted = true;
@ -94,35 +97,35 @@ public class ServerListManager implements Closeable {
} else {
this.namespace = namespace;
this.name = FIXED_NAME + "-" + getFixedNameSuffix(serverAddrs.toArray(new String[serverAddrs.size()])) + "-"
+ namespace;
+ namespace;
}
}
public ServerListManager(String host, int port) {
this.isFixed = false;
this.isStarted = false;
this.name = CUSTOM_NAME + "-" + host + "-" + port;
this.addressServerUrl = String.format("http://%s:%d/%s/%s", host, port, this.contentPath, this.serverListName);
}
public ServerListManager(String endpoint) throws NacosException {
this(endpoint, null);
}
public ServerListManager(String endpoint, String namespace) throws NacosException {
this.isFixed = false;
this.isStarted = false;
Properties properties = new Properties();
properties.setProperty(PropertyKeyConst.ENDPOINT, endpoint);
endpoint = initEndpoint(properties);
if (StringUtils.isBlank(endpoint)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "endpoint is blank");
}
if (StringUtils.isBlank(namespace)) {
this.name = endpoint;
this.addressServerUrl = String.format("http://%s:%d/%s/%s", endpoint, this.endpointPort, this.contentPath,
this.serverListName);
this.addressServerUrl = String
.format("http://%s:%d/%s/%s", endpoint, this.endpointPort, this.contentPath, this.serverListName);
} else {
if (StringUtils.isBlank(endpoint)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "endpoint is blank");
@ -130,24 +133,23 @@ public class ServerListManager implements Closeable {
this.name = endpoint + "-" + namespace;
this.namespace = namespace;
this.tenant = namespace;
this.addressServerUrl = String.format("http://%s:%d/%s/%s?namespace=%s", endpoint, this.endpointPort, this.contentPath,
this.serverListName, namespace);
this.addressServerUrl = String
.format("http://%s:%d/%s/%s?namespace=%s", endpoint, this.endpointPort, this.contentPath,
this.serverListName, namespace);
}
}
public ServerListManager(Properties properties) throws NacosException {
this.isStarted = false;
this.serverAddrsStr = properties.getProperty(PropertyKeyConst.SERVER_ADDR);
String namespace = properties.getProperty(PropertyKeyConst.NAMESPACE);
initParam(properties);
if (StringUtils.isNotEmpty(serverAddrsStr)) {
this.isFixed = true;
List<String> serverAddrs = new ArrayList<String>();
String[] serverAddrsArr = this.serverAddrsStr.split(",");
for (String serverAddr: serverAddrsArr) {
for (String serverAddr : serverAddrsArr) {
if (serverAddr.startsWith(HTTPS) || serverAddr.startsWith(HTTP)) {
serverAddrs.add(serverAddr);
} else {
@ -161,12 +163,13 @@ public class ServerListManager implements Closeable {
}
this.serverUrls = serverAddrs;
if (StringUtils.isBlank(namespace)) {
this.name = FIXED_NAME + "-" + getFixedNameSuffix(this.serverUrls.toArray(new String[this.serverUrls.size()]));
this.name = FIXED_NAME + "-" + getFixedNameSuffix(
this.serverUrls.toArray(new String[this.serverUrls.size()]));
} else {
this.namespace = namespace;
this.tenant = namespace;
this.name = FIXED_NAME + "-" + getFixedNameSuffix(this.serverUrls.toArray(new String[this.serverUrls.size()])) + "-"
+ namespace;
this.name = FIXED_NAME + "-" + getFixedNameSuffix(
this.serverUrls.toArray(new String[this.serverUrls.size()])) + "-" + namespace;
}
} else {
if (StringUtils.isBlank(endpoint)) {
@ -175,21 +178,23 @@ public class ServerListManager implements Closeable {
this.isFixed = false;
if (StringUtils.isBlank(namespace)) {
this.name = endpoint;
this.addressServerUrl = String.format("http://%s:%d/%s/%s", this.endpoint, this.endpointPort, this.contentPath,
this.serverListName);
this.addressServerUrl = String
.format("http://%s:%d/%s/%s", this.endpoint, this.endpointPort, this.contentPath,
this.serverListName);
} else {
this.namespace = namespace;
this.tenant = namespace;
this.name = this.endpoint + "-" + namespace;
this.addressServerUrl = String.format("http://%s:%d/%s/%s?namespace=%s", this.endpoint, this.endpointPort,
this.contentPath, this.serverListName, namespace);
this.addressServerUrl = String
.format("http://%s:%d/%s/%s?namespace=%s", this.endpoint, this.endpointPort, this.contentPath,
this.serverListName, namespace);
}
}
}
private void initParam(Properties properties) {
this.endpoint = initEndpoint(properties);
String contentPathTmp = properties.getProperty(PropertyKeyConst.CONTEXT_PATH);
if (!StringUtils.isBlank(contentPathTmp)) {
this.contentPath = contentPathTmp;
@ -199,27 +204,28 @@ public class ServerListManager implements Closeable {
this.serverListName = serverListNameTmp;
}
}
private String initEndpoint(final Properties properties) {
String endpointPortTmp = TemplateUtils.stringEmptyAndThenExecute(System.getenv(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_PORT), new Callable<String>() {
@Override
public String call() {
return properties.getProperty(PropertyKeyConst.ENDPOINT_PORT);
}
});
String endpointPortTmp = TemplateUtils
.stringEmptyAndThenExecute(System.getenv(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_PORT),
new Callable<String>() {
@Override
public String call() {
return properties.getProperty(PropertyKeyConst.ENDPOINT_PORT);
}
});
if (StringUtils.isNotBlank(endpointPortTmp)) {
this.endpointPort = Integer.parseInt(endpointPortTmp);
}
String endpointTmp = properties.getProperty(PropertyKeyConst.ENDPOINT);
// Whether to enable domain name resolution rules
String isUseEndpointRuleParsing =
properties.getProperty(PropertyKeyConst.IS_USE_ENDPOINT_PARSING_RULE,
String isUseEndpointRuleParsing = properties.getProperty(PropertyKeyConst.IS_USE_ENDPOINT_PARSING_RULE,
System.getProperty(SystemPropertyKeyConst.IS_USE_ENDPOINT_PARSING_RULE,
String.valueOf(ParamUtil.USE_ENDPOINT_PARSING_RULE_DEFAULT_VALUE)));
String.valueOf(ParamUtil.USE_ENDPOINT_PARSING_RULE_DEFAULT_VALUE)));
if (Boolean.parseBoolean(isUseEndpointRuleParsing)) {
String endpointUrl = ParamUtil.parsingEndpointRule(endpointTmp);
if (StringUtils.isNotBlank(endpointUrl)) {
@ -227,16 +233,21 @@ public class ServerListManager implements Closeable {
}
return endpointUrl;
}
return StringUtils.isNotBlank(endpointTmp) ? endpointTmp : "";
}
/**
* Start.
*
* @throws NacosException nacos exception
*/
public synchronized void start() throws NacosException {
if (isStarted || isFixed) {
return;
}
GetServerListTask getServersTask = new GetServerListTask(addressServerUrl);
for (int i = 0; i < initServerlistRetryTimes && serverUrls.isEmpty(); ++i) {
getServersTask.run();
@ -246,65 +257,65 @@ public class ServerListManager implements Closeable {
LOGGER.warn("get serverlist fail,url: {}", addressServerUrl);
}
}
if (serverUrls.isEmpty()) {
LOGGER.error("[init-serverlist] fail to get NACOS-server serverlist! env: {}, url: {}", name,
addressServerUrl);
addressServerUrl);
throw new NacosException(NacosException.SERVER_ERROR,
"fail to get NACOS-server serverlist! env:" + name + ", not connnect url:" + addressServerUrl);
"fail to get NACOS-server serverlist! env:" + name + ", not connnect url:" + addressServerUrl);
}
// executor schedules the timer task
this.executorService.scheduleWithFixedDelay(getServersTask,0L, 30L, TimeUnit.SECONDS);
this.executorService.scheduleWithFixedDelay(getServersTask, 0L, 30L, TimeUnit.SECONDS);
isStarted = true;
}
public List<String> getServerUrls() {
return serverUrls;
}
Iterator<String> iterator() {
if (serverUrls.isEmpty()) {
LOGGER.error("[{}] [iterator-serverlist] No server address defined!", name);
}
return new ServerAddressIterator(serverUrls);
}
@Override
public void shutdown() throws NacosException{
public void shutdown() throws NacosException {
String className = this.getClass().getName();
LOGGER.info("{} do shutdown begin", className);
ThreadUtils.shutdownThreadPool(executorService, LOGGER);
LOGGER.info("{} do shutdown stop", className);
}
class GetServerListTask implements Runnable {
final String url;
GetServerListTask(String url) {
this.url = url;
}
@Override
public void run() {
/**
* get serverlist from nameserver
/*
get serverlist from nameserver
*/
try {
updateIfChanged(getApacheServerList(url, name));
} catch (Exception e) {
LOGGER.error("[" + name + "][update-serverlist] failed to update serverlist from address server!",
e);
LOGGER.error("[" + name + "][update-serverlist] failed to update serverlist from address server!", e);
}
}
}
private void updateIfChanged(List<String> newList) {
if (null == newList || newList.isEmpty()) {
LOGGER.warn("[update-serverlist] current serverlist from address server is empty!!!");
return;
}
List<String> newServerAddrList = new ArrayList<String>();
for (String server : newList) {
if (server.startsWith(HTTP) || server.startsWith(HTTPS)) {
@ -313,9 +324,9 @@ public class ServerListManager implements Closeable {
newServerAddrList.add(HTTP + server);
}
}
/**
* no change
/*
no change
*/
if (newServerAddrList.equals(serverUrls)) {
return;
@ -323,15 +334,15 @@ public class ServerListManager implements Closeable {
serverUrls = new ArrayList<String>(newServerAddrList);
iterator = iterator();
currentServerAddr = iterator.next();
EventDispatcher.fireEvent(new ServerlistChangeEvent());
LOGGER.info("[{}] [update-serverlist] serverlist updated to {}", name, serverUrls);
}
private List<String> getApacheServerList(String url, String name) {
try {
HttpResult httpResult = HttpSimpleClient.httpGet(url, null, null, null, 3000);
if (HttpURLConnection.HTTP_OK == httpResult.code) {
if (DEFAULT_NAME.equals(name)) {
EnvUtil.setSelfEnv(httpResult.headers);
@ -352,7 +363,7 @@ public class ServerListManager implements Closeable {
return result;
} else {
LOGGER.error("[check-serverlist] error. addressServerUrl: {}, code: {}", addressServerUrl,
httpResult.code);
httpResult.code);
return null;
}
} catch (IOException e) {
@ -360,11 +371,11 @@ public class ServerListManager implements Closeable {
return null;
}
}
String getUrlString() {
return serverUrls.toString();
}
String getFixedNameSuffix(String... serverIps) {
StringBuilder sb = new StringBuilder();
String split = "";
@ -376,22 +387,22 @@ public class ServerListManager implements Closeable {
}
return sb.toString();
}
@Override
public String toString() {
return "ServerManager-" + name + "-" + getUrlString();
}
public boolean contain(String ip) {
return serverUrls.contains(ip);
}
public void refreshCurrentServerAddr() {
iterator = iterator();
currentServerAddr = iterator.next();
}
public String getCurrentServerAddr() {
if (StringUtils.isBlank(currentServerAddr)) {
iterator = iterator();
@ -399,124 +410,140 @@ public class ServerListManager implements Closeable {
}
return currentServerAddr;
}
public void updateCurrentServerAddr(String currentServerAddr) {
this.currentServerAddr = currentServerAddr;
}
public Iterator<String> getIterator() {
return iterator;
}
public String getContentPath() {
return contentPath;
}
public String getName() {
return name;
}
public String getNamespace() {
return namespace;
}
public String getTenant() {
return tenant;
}
/**
* The name of the different environment
* The name of the different environment.
*/
private String name;
private final String name;
private String namespace = "";
private String tenant = "";
static public final String DEFAULT_NAME = "default";
static public final String CUSTOM_NAME = "custom";
static public final String FIXED_NAME = "fixed";
private int initServerlistRetryTimes = 5;
public static final String DEFAULT_NAME = "default";
public static final String CUSTOM_NAME = "custom";
public static final String FIXED_NAME = "fixed";
private final int initServerlistRetryTimes = 5;
/**
* Connection timeout and socket timeout with other servers
* Connection timeout and socket timeout with other servers.
*/
static final int TIMEOUT = 5000;
final boolean isFixed;
boolean isStarted = false;
private String endpoint;
private int endpointPort = 8080;
private String contentPath = ParamUtil.getDefaultContextPath();
private String serverListName = ParamUtil.getDefaultNodesPath();
volatile List<String> serverUrls = new ArrayList<String>();
private volatile String currentServerAddr;
private Iterator<String> iterator;
public String serverPort = ParamUtil.getDefaultServerPort();
public String addressServerUrl;
private String serverAddrsStr;
}
/**
* Sort the address list, with the same room priority.
*/
class ServerAddressIterator implements Iterator<String> {
static class RandomizedServerAddress implements Comparable<RandomizedServerAddress> {
static Random random = new Random();
String serverIp;
int priority = 0;
int seed;
public RandomizedServerAddress(String ip) {
try {
this.serverIp = ip;
/**
* change random scope from 32 to Integer.MAX_VALUE to fix load balance issue
*/
this.seed = random.nextInt(Integer.MAX_VALUE);
} catch (Exception e) {
throw new RuntimeException(e);
/**
* Sort the address list, with the same room priority.
*/
private static class ServerAddressIterator implements Iterator<String> {
static class RandomizedServerAddress implements Comparable<RandomizedServerAddress> {
static Random random = new Random();
String serverIp;
int priority = 0;
int seed;
public RandomizedServerAddress(String ip) {
try {
this.serverIp = ip;
/*
change random scope from 32 to Integer.MAX_VALUE to fix load balance issue
*/
this.seed = random.nextInt(Integer.MAX_VALUE);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public int compareTo(RandomizedServerAddress other) {
if (this.priority != other.priority) {
return other.priority - this.priority;
} else {
return other.seed - this.seed;
}
}
}
public ServerAddressIterator(List<String> source) {
sorted = new ArrayList<RandomizedServerAddress>();
for (String address : source) {
sorted.add(new RandomizedServerAddress(address));
}
Collections.sort(sorted);
iter = sorted.iterator();
}
@Override
public int compareTo(RandomizedServerAddress other) {
if (this.priority != other.priority) {
return other.priority - this.priority;
} else {
return other.seed - this.seed;
}
public boolean hasNext() {
return iter.hasNext();
}
}
public ServerAddressIterator(List<String> source) {
sorted = new ArrayList<RandomizedServerAddress>();
for (String address : source) {
sorted.add(new RandomizedServerAddress(address));
@Override
public String next() {
return iter.next().serverIp;
}
Collections.sort(sorted);
iter = sorted.iterator();
@Override
public void remove() {
throw new UnsupportedOperationException();
}
final List<RandomizedServerAddress> sorted;
final Iterator<RandomizedServerAddress> iter;
}
@Override
public boolean hasNext() {
return iter.hasNext();
}
@Override
public String next() {
return iter.next().serverIp;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
final List<RandomizedServerAddress> sorted;
final Iterator<RandomizedServerAddress> iter;
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.impl;
import com.alibaba.nacos.api.common.Constants;
@ -23,15 +24,20 @@ import com.alibaba.nacos.common.utils.StringUtils;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* 适配spas接口
* 适配spas接口.
*
* @author Nacos
*/
public class SpasAdapter {
public static List<String> getSignHeaders(String resource, String secretKey) {
List<String> header = new ArrayList<String>();
String timeStamp = String.valueOf(System.currentTimeMillis());
@ -41,15 +47,15 @@ public class SpasAdapter {
header.add("Spas-Signature");
String signature = "";
if (StringUtils.isBlank(resource)) {
signature = signWithhmacSHA1Encrypt(timeStamp, secretKey);
signature = signWithHmacSha1Encrypt(timeStamp, secretKey);
} else {
signature = signWithhmacSHA1Encrypt(resource + "+" + timeStamp, secretKey);
signature = signWithHmacSha1Encrypt(resource + "+" + timeStamp, secretKey);
}
header.add(signature);
}
return header;
}
public static List<String> getSignHeaders(List<String> paramValues, String secretKey) {
if (null == paramValues) {
return null;
@ -73,25 +79,32 @@ public class SpasAdapter {
}
return getSignHeaders(resource, secretKey);
}
public static String getSk() {
return CredentialService.getInstance().getCredential().getSecretKey();
}
public static String getAk() {
return CredentialService.getInstance().getCredential().getAccessKey();
}
public static String signWithhmacSHA1Encrypt(String encryptText, String encryptKey) {
/**
* Sign with hmac SHA1 encrtpt.
*
* @param encryptText encrypt text
* @param encryptKey encrypt key
* @return base64 string
*/
public static String signWithHmacSha1Encrypt(String encryptText, String encryptKey) {
try {
byte[] data = encryptKey.getBytes("UTF-8");
byte[] data = encryptKey.getBytes(StandardCharsets.UTF_8);
// 根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
SecretKey secretKey = new SecretKeySpec(data, "HmacSHA1");
// 生成一个指定 Mac 算法 Mac 对象
Mac mac = Mac.getInstance("HmacSHA1");
// 用给定密钥初始化 Mac 对象
mac.init(secretKey);
byte[] text = encryptText.getBytes("UTF-8");
byte[] text = encryptText.getBytes(StandardCharsets.UTF_8);
byte[] textFinal = mac.doFinal(text);
// 完成 Mac 操作, base64编码将byte数组转换为字符串
return new String(Base64.encodeBase64(textFinal), Constants.ENCODE);
@ -99,7 +112,8 @@ public class SpasAdapter {
throw new RuntimeException("signWithhmacSHA1Encrypt fail", e);
}
}
private static final String GROUP_KEY = "group";
public static final String TENANT_KEY = "tenant";
}

View File

@ -13,28 +13,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.impl;
import com.alibaba.nacos.api.config.ConfigChangeItem;
import com.alibaba.nacos.common.utils.StringUtils;
import org.yaml.snakeyaml.Yaml;
import java.util.*;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* YmlChangeParser
* YmlChangeParser.
*
* @author rushsky518
*/
public class YmlChangeParser extends AbstractConfigChangeParser {
public YmlChangeParser() {
super("yaml");
}
@Override
public Map<String, ConfigChangeItem> doParse(String oldContent, String newContent, String type) {
Map<String, Object> oldMap = Collections.emptyMap();
Map<String, Object> newMap = Collections.emptyMap();
if (StringUtils.isNotBlank(oldContent)) {
oldMap = (new Yaml()).load(oldContent);
oldMap = getFlattenedMap(oldMap);
@ -43,16 +50,16 @@ public class YmlChangeParser extends AbstractConfigChangeParser {
newMap = (new Yaml()).load(newContent);
newMap = getFlattenedMap(newMap);
}
return filterChangeData(oldMap, newMap);
}
private final Map<String, Object> getFlattenedMap(Map<String, Object> source) {
Map<String, Object> result = new LinkedHashMap<String, Object>(128);
buildFlattenedMap(result, source, null);
return result;
}
private void buildFlattenedMap(Map<String, Object> result, Map<String, Object> source, String path) {
for (Iterator<Map.Entry<String, Object>> itr = source.entrySet().iterator(); itr.hasNext(); ) {
Map.Entry<String, Object> e = itr.next();
@ -67,12 +74,10 @@ public class YmlChangeParser extends AbstractConfigChangeParser {
if (e.getValue() instanceof String) {
result.put(key, e.getValue());
} else if (e.getValue() instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) e.getValue();
@SuppressWarnings("unchecked") Map<String, Object> map = (Map<String, Object>) e.getValue();
buildFlattenedMap(result, map, key);
} else if (e.getValue() instanceof Collection) {
@SuppressWarnings("unchecked")
Collection<Object> collection = (Collection<Object>) e.getValue();
@SuppressWarnings("unchecked") Collection<Object> collection = (Collection<Object>) e.getValue();
if (collection.isEmpty()) {
result.put(key, "");
} else {
@ -86,5 +91,5 @@ public class YmlChangeParser extends AbstractConfigChangeParser {
}
}
}
}

View File

@ -13,24 +13,28 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.listener.impl;
import com.alibaba.nacos.api.config.listener.AbstractListener;
import com.alibaba.nacos.api.config.ConfigChangeEvent;
import com.alibaba.nacos.api.config.listener.AbstractListener;
/**
* AbstractConfigChangeListener
* AbstractConfigChangeListener.
*
* @author rushsky518
*/
public abstract class AbstractConfigChangeListener extends AbstractListener {
/**
* handle config change
* @param event
* handle config change.
*
* @param event config change event
*/
public abstract void receiveConfigChange(final ConfigChangeEvent event);
@Override
public void receiveConfigInfo(final String configInfo) {}
public void receiveConfigInfo(final String configInfo) {
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.listener.impl;
import com.alibaba.nacos.api.config.listener.AbstractListener;
@ -25,21 +26,21 @@ import java.io.StringReader;
import java.util.Properties;
/**
* Properties Listener
* Properties Listener.
*
* @author Nacos
*/
@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule")
public abstract class PropertiesListener extends AbstractListener {
private static final Logger LOGGER = LogUtils.logger(PropertiesListener.class);
@Override
public void receiveConfigInfo(String configInfo) {
if (StringUtils.isEmpty(configInfo)) {
return;
}
Properties properties = new Properties();
try {
properties.load(new StringReader(configInfo));
@ -47,14 +48,14 @@ public abstract class PropertiesListener extends AbstractListener {
} catch (IOException e) {
LOGGER.error("load properties error" + configInfo, e);
}
}
/**
* properties type for receiver
* properties type for receiver.
*
* @param properties properties
*/
public abstract void innerReceive(Properties properties);
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.utils;
import org.slf4j.Logger;
@ -30,36 +31,34 @@ import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
/**
* concurrent disk util;op file with file lock
* concurrent disk util;op file with file lock.
*
* @author configCenter
*/
public class ConcurrentDiskUtil {
/**
* get file content
* get file content.
*
* @param path file path
* @param charsetName charsetName
* @return content
* @throws IOException IOException
*/
public static String getFileContent(String path, String charsetName)
throws IOException {
public static String getFileContent(String path, String charsetName) throws IOException {
File file = new File(path);
return getFileContent(file, charsetName);
}
/**
* get file content
* get file content.
*
* @param file file
* @param charsetName charsetName
* @return content
* @throws IOException IOException
*/
public static String getFileContent(File file, String charsetName)
throws IOException {
public static String getFileContent(File file, String charsetName) throws IOException {
RandomAccessFile fis = null;
FileLock rlock = null;
try {
@ -72,17 +71,14 @@ public class ConcurrentDiskUtil {
} catch (Exception e) {
++i;
if (i > RETRY_COUNT) {
LOGGER.error("read {} fail;retryed time:{}",
file.getName(), i);
throw new IOException("read " + file.getAbsolutePath()
+ " conflict");
LOGGER.error("read {} fail;retryed time:{}", file.getName(), i);
throw new IOException("read " + file.getAbsolutePath() + " conflict");
}
sleep(SLEEP_BASETIME * i);
LOGGER.warn("read {} conflict;retry time:{}", file.getName(),
i);
LOGGER.warn("read {} conflict;retry time:{}", file.getName(), i);
}
} while (null == rlock);
int fileSize = (int)fcin.size();
int fileSize = (int) fcin.size();
ByteBuffer byteBuffer = ByteBuffer.allocate(fileSize);
fcin.read(byteBuffer);
byteBuffer.flip();
@ -98,9 +94,9 @@ public class ConcurrentDiskUtil {
}
}
}
/**
* write file content
* write file content.
*
* @param path file path
* @param content content
@ -108,14 +104,13 @@ public class ConcurrentDiskUtil {
* @return whether write ok
* @throws IOException IOException
*/
public static Boolean writeFileContent(String path, String content,
String charsetName) throws IOException {
public static Boolean writeFileContent(String path, String content, String charsetName) throws IOException {
File file = new File(path);
return writeFileContent(file, content, charsetName);
}
/**
* write file content
* write file content.
*
* @param file file
* @param content content
@ -123,8 +118,7 @@ public class ConcurrentDiskUtil {
* @return whether write ok
* @throws IOException IOException
*/
public static Boolean writeFileContent(File file, String content,
String charsetName) throws IOException {
public static Boolean writeFileContent(File file, String content, String charsetName) throws IOException {
if (!file.exists()) {
boolean isCreateOk = file.createNewFile();
if (!isCreateOk) {
@ -144,19 +138,15 @@ public class ConcurrentDiskUtil {
} catch (Exception e) {
++i;
if (i > RETRY_COUNT) {
LOGGER.error("write {} fail;retryed time:{}",
file.getName(), i);
throw new IOException("write " + file.getAbsolutePath()
+ " conflict");
LOGGER.error("write {} fail;retryed time:{}", file.getName(), i);
throw new IOException("write " + file.getAbsolutePath() + " conflict");
}
sleep(SLEEP_BASETIME * i);
LOGGER.warn("write {} conflict;retry time:{}", file.getName(),
i);
LOGGER.warn("write {} conflict;retry time:{}", file.getName(), i);
}
} while (null == lock);
ByteBuffer sendBuffer = ByteBuffer.wrap(content
.getBytes(charsetName));
ByteBuffer sendBuffer = ByteBuffer.wrap(content.getBytes(charsetName));
while (sendBuffer.hasRemaining()) {
channel.write(sendBuffer);
}
@ -188,21 +178,20 @@ public class ConcurrentDiskUtil {
LOGGER.warn("close wrong", e);
}
}
}
return true;
}
/**
* transfer ByteBuffer to String
* transfer ByteBuffer to String.
*
* @param buffer buffer
* @param charsetName charsetName
* @return String
* @throws IOException IOException
*/
public static String byteBufferToString(ByteBuffer buffer,
String charsetName) throws IOException {
public static String byteBufferToString(ByteBuffer buffer, String charsetName) throws IOException {
Charset charset = null;
CharsetDecoder decoder = null;
CharBuffer charBuffer = null;
@ -211,7 +200,7 @@ public class ConcurrentDiskUtil {
charBuffer = decoder.decode(buffer.asReadOnlyBuffer());
return charBuffer.toString();
}
private static void sleep(int time) {
try {
Thread.sleep(time);
@ -219,11 +208,13 @@ public class ConcurrentDiskUtil {
LOGGER.warn("sleep wrong", e);
}
}
private static final Logger LOGGER = LoggerFactory.getLogger(ConcurrentDiskUtil.class);
static final int RETRY_COUNT = 10;
/**
* ms
* ms.
*/
static final int SLEEP_BASETIME = 10;
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.utils;
import com.alibaba.nacos.api.common.Constants;
@ -20,14 +21,20 @@ import com.alibaba.nacos.api.common.Constants;
import static com.alibaba.nacos.api.common.Constants.WORD_SEPARATOR;
/**
* Content Util
* Content Util.
*
* @author Nacos
*/
public class ContentUtils {
/**
* Verify increment pub content.
*
* @param content content
* @throws IllegalArgumentException if content is not valid
*/
public static void verifyIncrementPubContent(String content) {
if (content == null || content.length() == 0) {
throw new IllegalArgumentException("发布/删除内容不能为空");
}
@ -41,7 +48,7 @@ public class ContentUtils {
}
}
}
public static String getContentIdentity(String content) {
int index = content.indexOf(WORD_SEPARATOR);
if (index == -1) {
@ -49,7 +56,7 @@ public class ContentUtils {
}
return content.substring(0, index);
}
public static String getContent(String content) {
int index = content.indexOf(WORD_SEPARATOR);
if (index == -1) {
@ -57,7 +64,13 @@ public class ContentUtils {
}
return content.substring(index + 1);
}
/**
* Truncate content.
*
* @param content content
* @return truncated content
*/
public static String truncateContent(String content) {
if (content == null) {
return "";
@ -67,6 +80,6 @@ public class ContentUtils {
return content.substring(0, SHOW_CONTENT_SIZE) + "...";
}
}
private static int SHOW_CONTENT_SIZE = 100;
private static final int SHOW_CONTENT_SIZE = 100;
}

View File

@ -13,32 +13,34 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.utils;
import com.alibaba.nacos.client.utils.LogUtils;
import org.slf4j.Logger;
/**
* Get jvm config
* Get jvm config.
*
* @author Nacos
*/
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
public class JVMUtil {
public class JvmUtil {
/**
* whether is multi instance
* whether is multi instance.
*
* @return whether multi
*/
public static Boolean isMultiInstance() {
return isMultiInstance;
}
private static Boolean isMultiInstance = false;
private static final String TRUE = "true";
private static final Logger LOGGER = LogUtils.logger(JVMUtil.class);
private static final Logger LOGGER = LogUtils.logger(JvmUtil.class);
static {
String multiDeploy = System.getProperty("isMultiInstance", "false");
if (TRUE.equals(multiDeploy)) {

View File

@ -13,28 +13,29 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.utils;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.client.utils.IPUtil;
import com.alibaba.nacos.client.utils.IpUtil;
import com.alibaba.nacos.common.utils.StringUtils;
import java.util.List;
/**
* Param check util
* Param check util.
*
* @author Nacos
*/
public class ParamUtils {
private static char[] validChars = new char[] {'_', '-', '.', ':'};
private static final char[] VALID_CHARS = new char[] {'_', '-', '.', ':'};
/**
* 白名单的方式检查, 合法的参数只能包含字母数字以及validChars中的字符, 并且不能为空
* 白名单的方式检查, 合法的参数只能包含字母数字以及validChars中的字符, 并且不能为空.
*
* @param param
* @return
* @param param parameter
* @return true if valid
*/
public static boolean isValid(String param) {
if (param == null) {
@ -49,26 +50,25 @@ public class ParamUtils {
}
return true;
}
private static boolean isValidChar(char ch) {
for (char c : validChars) {
for (char c : VALID_CHARS) {
if (c == ch) {
return true;
}
}
return false;
}
public static void checkKeyParam(String dataId, String group) throws NacosException {
if (StringUtils.isBlank(dataId) || !ParamUtils.isValid(dataId)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "dataId invalid");
}
if (StringUtils.isBlank(group) || !ParamUtils.isValid(group)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "group invalid");
}
}
public static void checkTDG(String tenant, String dataId, String group) throws NacosException {
/**
* Check Tenant, dataId and group.
*
* @param tenant tenant
* @param dataId dataId
* @param group group
* @throws NacosException nacos exception
*/
public static void checkTdg(String tenant, String dataId, String group) throws NacosException {
checkTenant(tenant);
if (StringUtils.isBlank(dataId) || !ParamUtils.isValid(dataId)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "dataId invalid");
@ -77,9 +77,32 @@ public class ParamUtils {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "group invalid");
}
}
public static void checkKeyParam(String dataId, String group, String datumId)
throws NacosException {
/**
* Check key param.
*
* @param dataId dataId
* @param group group
* @throws NacosException nacos exception
*/
public static void checkKeyParam(String dataId, String group) throws NacosException {
if (StringUtils.isBlank(dataId) || !ParamUtils.isValid(dataId)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "dataId invalid");
}
if (StringUtils.isBlank(group) || !ParamUtils.isValid(group)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "group invalid");
}
}
/**
* Check key param.
*
* @param dataId dataId
* @param group group
* @param datumId datumId
* @throws NacosException nacos exception
*/
public static void checkKeyParam(String dataId, String group, String datumId) throws NacosException {
if (StringUtils.isBlank(dataId) || !ParamUtils.isValid(dataId)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "dataId invalid");
}
@ -90,7 +113,14 @@ public class ParamUtils {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "datumId invalid");
}
}
/**
* Check key param.
*
* @param dataIds dataIds
* @param group group
* @throws NacosException nacos exception
*/
public static void checkKeyParam(List<String> dataIds, String group) throws NacosException {
if (dataIds == null || dataIds.size() == 0) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "dataIds invalid");
@ -104,39 +134,74 @@ public class ParamUtils {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "group invalid");
}
}
/**
* Check parameter.
*
* @param dataId dataId
* @param group group
* @param content content
* @throws NacosException nacos exception
*/
public static void checkParam(String dataId, String group, String content) throws NacosException {
checkKeyParam(dataId, group);
if (StringUtils.isBlank(content)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "content invalid");
}
}
/**
* Check parameter.
*
* @param dataId dataId
* @param group group
* @param datumId datumId
* @param content content
* @throws NacosException nacos exception
*/
public static void checkParam(String dataId, String group, String datumId, String content) throws NacosException {
checkKeyParam(dataId, group, datumId);
if (StringUtils.isBlank(content)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "content invalid");
}
}
/**
* Check Tenant.
*
* @param tenant tenant
* @throws NacosException nacos exception
*/
public static void checkTenant(String tenant) throws NacosException {
if (StringUtils.isBlank(tenant) || !ParamUtils.isValid(tenant)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "tenant invalid");
}
}
/**
* Check beta ips.
*
* @param betaIps beta ips
* @throws NacosException nacos exception
*/
public static void checkBetaIps(String betaIps) throws NacosException {
if (StringUtils.isBlank(betaIps)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "betaIps invalid");
}
String[] ipsArr = betaIps.split(",");
for (String ip : ipsArr) {
if (!IPUtil.isIPV4(ip)) {
if (!IpUtil.isIpv4(ip)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "betaIps invalid");
}
}
}
/**
* Check content.
*
* @param content content
* @throws NacosException nacos exception
*/
public static void checkContent(String content) throws NacosException {
if (StringUtils.isBlank(content)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "content invalid");

View File

@ -13,29 +13,30 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.utils;
import com.alibaba.nacos.client.config.impl.LocalConfigInfoProcessor;
/**
* Snapshot switch
* Snapshot switch.
*
* @author Nacos
*/
public class SnapShotSwitch {
/**
* whether use local cache
* whether use local cache.
*/
private static Boolean isSnapShot = true;
public static Boolean getIsSnapShot() {
return isSnapShot;
}
public static void setIsSnapShot(Boolean isSnapShot) {
SnapShotSwitch.isSnapShot = isSnapShot;
LocalConfigInfoProcessor.cleanAllSnapshot();
}
}

View File

@ -13,14 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.identify;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
/**
* Provides Base64 encoding and decoding as defined by <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>.
* <p>
* <p> This class implements section <cite>6.8. Base64 Content-Transfer-Encoding</cite> from RFC 2045 <cite>Multipurpose
*
* <p>This class implements section <cite>6.8. Base64 Content-Transfer-Encoding</cite> from RFC 2045
*
* <cite>Multipurpose
* Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies</cite> by Freed and Borenstein. </p> <p>
* The class can be parameterized in the following manner with various constructors: <ul> <li>URL-safe mode: Default
* off.</li> <li>Line length: Default 76. Line length that aren't multiples of 4 will still essentially end up being
@ -35,129 +38,120 @@ import java.io.UnsupportedEncodingException;
* @since 1.0
*/
public class Base64 {
/**
* BASE32 characters are 6 bits in length. They are formed by taking a block of 3 octets to form a 24-bit string,
* which is converted into 4 BASE64 characters.
*/
private static final int BITS_PER_ENCODED_BYTE = 6;
private static final int BYTES_PER_UNENCODED_BLOCK = 3;
private static final int BYTES_PER_ENCODED_BLOCK = 4;
/**
* Chunk separator per RFC 2045 section 2.1.
* <p>
* <p> N.B. The next major release may break compatibility and make this field private. </p>
*
* <p>N.B. The next major release may break compatibility and make this field private. </p>
*
* @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 2.1</a>
*/
static final byte[] CHUNK_SEPARATOR = {'\r', '\n'};
/**
* This array is a lookup table that translates 6-bit positive integer index values into their "Base64 Alphabet"
* equivalents as specified in Table 1 of RFC 2045.
* <p>
* Thanks to "commons" project in ws.apache.org for this code. http://svn.apache
* .org/repos/asf/webservices/commons/trunk/modules/util/
*
* <p>Thanks to "commons" project in ws.apache.org for this code.
*
* <p>http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
*/
private static final byte[] STANDARD_ENCODE_TABLE = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
};
private static final byte[] STANDARD_ENCODE_TABLE = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1',
'2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
/**
* This is a copy of the STANDARD_ENCODE_TABLE above, but with + and / changed to - and _ to make the encoded Base64
* results more URL-SAFE. This table is only used when the Base64's mode is set to URL-SAFE.
*/
private static final byte[] URL_SAFE_ENCODE_TABLE = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
};
private static final byte[] URL_SAFE_ENCODE_TABLE = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1',
'2', '3', '4', '5', '6', '7', '8', '9', '-', '_'};
/**
* This array is a lookup table that translates Unicode characters drawn from the "Base64 Alphabet" (as specified in
* Table 1 of RFC 2045) into their 6-bit positive integer equivalents. Characters that are not in the Base64
* alphabet but fall within the bounds of the array are translated to -1.
* <p>
* Note: '+' and '-' both decode to 62. '/' and '_' both decode to 63. This means decoder seamlessly handles both
* URL_SAFE and STANDARD base64. (The encoder, on the other hand, needs to know ahead of time what to emit).
* <p>
* Thanks to "commons" project in ws.apache.org for this code. http://svn.apache
* .org/repos/asf/webservices/commons/trunk/modules/util/
*
* <p>Note: '+' and '-' both decode to 62. '/' and '_' both decode to 63. This means decoder seamlessly handles
* both URL_SAFE and STANDARD base64. (The encoder, on the other hand, needs to know ahead of time what to emit).
*
* <p>Thanks to "commons" project in ws.apache.org for this code.
*
* <p>http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
*/
private static final byte[] DECODE_TABLE = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, -1, -1, -1, -1, 63, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
};
private static final byte[] DECODE_TABLE = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1,
62, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, -1, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51};
/**
* Base64 uses 6-bit fields.
*/
/**
* Mask used to extract 6 bits, used when encoding
* Base64 uses 6-bit fields. Mask used to extract 6 bits, used when encoding
*/
private static final int MASK_6BITS = 0x3f;
// The static final fields above are used for the original static byte[] methods on Base64.
// The private member fields below are used with the new streaming approach, which requires
// some state be preserved between calls of encode() and decode().
/**
* Encode table to use: either STANDARD or URL_SAFE. Note: the DECODE_TABLE above remains static because it is able
* to decode both STANDARD and URL_SAFE streams, but the encodeTable must be a member variable so we can switch
* between the two modes.
*/
private final byte[] encodeTable;
/**
* Only one decode table currently; keep for consistency with Base32 code
* Only one decode table currently; keep for consistency with Base32 code.
*/
private final byte[] decodeTable = DECODE_TABLE;
/**
* Line separator for encoding. Not used when decoding. Only used if lineLength > 0.
*/
private final byte[] lineSeparator;
/**
* Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
* <code>decodeSize = 3 + lineSeparator.length;</code>
*/
private final int decodeSize;
/**
* Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
* <code>encodeSize = 4 + lineSeparator.length;</code>
*/
private final int encodeSize;
/**
* Place holder for the bytes we're dealing with for our based logic. Bitwise operations store and extract the
* encoding or decoding from this variable.
*/
private int bitWorkArea;
/**
* Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. <p> When encoding the line
* length is 0 (no chunking), and the encoding table is STANDARD_ENCODE_TABLE. </p>
* <p>
* <p> When decoding all variants are supported. </p>
*
* <p>When decoding all variants are supported. </p>
*/
public Base64() {
this(0, CHUNK_SEPARATOR, false);
}
/**
* Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. <p> When encoding the line
* length and line separator are given in the constructor, and the encoding table is STANDARD_ENCODE_TABLE. </p> <p>
@ -178,17 +172,14 @@ public class Base64 {
chunkSeparatorLength = lineSeparator == null ? 0 : lineSeparator.length;
unencodedBlockSize = BYTES_PER_UNENCODED_BLOCK;
encodedBlockSize = BYTES_PER_ENCODED_BLOCK;
this.lineLength = (lineLength > 0 && chunkSeparatorLength > 0) ? (lineLength / encodedBlockSize)
* encodedBlockSize : 0;
this.lineLength =
(lineLength > 0 && chunkSeparatorLength > 0) ? (lineLength / encodedBlockSize) * encodedBlockSize : 0;
// TODO could be simplified if there is no requirement to reject invalid line sep when length <=0
// @see test case Base64Test.testConstructors()
if (lineSeparator != null) {
if (containsAlphabetOrPad(lineSeparator)) {
String sep = null;
try {
sep = new String(lineSeparator, "UTF-8");
} catch (UnsupportedEncodingException e) {
}
sep = new String(lineSeparator, StandardCharsets.UTF_8);
throw new IllegalArgumentException("lineSeparator must not contain base64 characters: [" + sep + "]");
}
if (lineLength > 0) {
@ -206,7 +197,25 @@ public class Base64 {
this.decodeSize = this.encodeSize - 1;
this.encodeTable = urlSafe ? URL_SAFE_ENCODE_TABLE : STANDARD_ENCODE_TABLE;
}
/**
* Encodes a byte[] containing binary data, into a byte[] containing characters in the alphabet.
*
* @param pArray a byte array containing binary data
* @return A byte array containing only the basen alphabetic character data
*/
private byte[] encode(byte[] pArray) {
reset();
if (pArray == null || pArray.length == 0) {
return pArray;
}
encode(pArray, 0, pArray.length);
encode(pArray, 0, -1);
byte[] buf = new byte[pos - readPos];
readResults(buf, 0, buf.length);
return buf;
}
/**
* <p> Encodes all of the provided data, starting at inPos, for inAvail bytes. Must be called at least twice: once
* with the data to encode, and once with inAvail set to "-1" to alert encoder that EOF has been reached, so flush
@ -233,18 +242,18 @@ public class Base64 {
case 1:
buffer[pos++] = encodeTable[(bitWorkArea >> 2) & MASK_6BITS];
buffer[pos++] = encodeTable[(bitWorkArea << 4) & MASK_6BITS];
if (encodeTable == STANDARD_ENCODE_TABLE) {
buffer[pos++] = PAD;
buffer[pos++] = PAD;
}
break;
case 2:
buffer[pos++] = encodeTable[(bitWorkArea >> 10) & MASK_6BITS];
buffer[pos++] = encodeTable[(bitWorkArea >> 4) & MASK_6BITS];
buffer[pos++] = encodeTable[(bitWorkArea << 2) & MASK_6BITS];
if (encodeTable == STANDARD_ENCODE_TABLE) {
buffer[pos++] = PAD;
}
@ -253,8 +262,8 @@ public class Base64 {
break;
}
currentLinePos += pos - savedPos;
/**
* if currentPos == 0 we are at the start of a line, so don't add CRLF
/*
if currentPos == 0 we are at the start of a line, so don't add CRLF
*/
if (lineLength > 0 && currentLinePos > 0) {
System.arraycopy(lineSeparator, 0, buffer, pos, lineSeparator.length);
@ -284,14 +293,32 @@ public class Base64 {
}
}
}
/**
* <p> Decodes all of the provided data, starting at inPos, for inAvail bytes. Should be called at least twice: once
* with the data to decode, and once with inAvail set to "-1" to alert decoder that EOF has been reached. The "-1"
* call is not necessary when decoding, but it doesn't hurt, either. </p> <p> Ignores all non-base64 characters.
* This is how chunked (e.g. 76 character) data is handled, since CR and LF are silently ignored, but has
* implications for other bytes, too. This method subscribes to the garbage-in, garbage-out philosophy: it will not
* check the provided data for validity. </p> <p> Thanks to "commons" project in ws.apache.org for the bitwise
* Decodes a byte[] containing characters in the Base-N alphabet.
*
* @param pArray A byte array containing Base-N character data
* @return a byte array containing binary data
*/
private byte[] decode(byte[] pArray) {
reset();
if (pArray == null || pArray.length == 0) {
return pArray;
}
decode(pArray, 0, pArray.length);
decode(pArray, 0, -1);
byte[] result = new byte[pos];
readResults(result, 0, result.length);
return result;
}
/**
* <p> Decodes all of the provided data, starting at inPos, for inAvail bytes. Should be called at least twice:
* once with the data to decode, and once with inAvail set to "-1" to alert decoder that EOF has been reached. The
* "-1" call is not necessary when decoding, but it doesn't hurt, either. </p> <p> Ignores all non-base64
* characters. This is how chunked (e.g. 76 character) data is handled, since CR and LF are silently ignored, but
* has implications for other bytes, too. This method subscribes to the garbage-in, garbage-out philosophy: it will
* not check the provided data for validity. </p> <p> Thanks to "commons" project in ws.apache.org for the bitwise
* operations, and general approach. http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ </p>
*
* @param in byte[] array of ascii data to base64 decode.
@ -319,21 +346,21 @@ public class Base64 {
modulus = (modulus + 1) % BYTES_PER_ENCODED_BLOCK;
bitWorkArea = (bitWorkArea << BITS_PER_ENCODED_BYTE) + result;
if (modulus == 0) {
buffer[pos++] = (byte)((bitWorkArea >> 16) & MASK_8BITS);
buffer[pos++] = (byte)((bitWorkArea >> 8) & MASK_8BITS);
buffer[pos++] = (byte)(bitWorkArea & MASK_8BITS);
buffer[pos++] = (byte) ((bitWorkArea >> 16) & MASK_8BITS);
buffer[pos++] = (byte) ((bitWorkArea >> 8) & MASK_8BITS);
buffer[pos++] = (byte) (bitWorkArea & MASK_8BITS);
}
}
}
}
}
// Two forms of EOF as far as base64 decoder is concerned: actual
// EOF (-1) and first time '=' character is encountered in stream.
// This approach makes the '=' padding characters completely optional.
if (eof && modulus != 0) {
ensureBufferSize(decodeSize);
// We have some spare bits remaining
// Output all whole multiples of 8 bits and ignore the rest
switch (modulus) {
@ -341,19 +368,19 @@ public class Base64 {
// break;
case 2:
bitWorkArea = bitWorkArea >> 4;
buffer[pos++] = (byte)((bitWorkArea) & MASK_8BITS);
buffer[pos++] = (byte) ((bitWorkArea) & MASK_8BITS);
break;
case 3:
bitWorkArea = bitWorkArea >> 2;
buffer[pos++] = (byte)((bitWorkArea >> 8) & MASK_8BITS);
buffer[pos++] = (byte)((bitWorkArea) & MASK_8BITS);
buffer[pos++] = (byte) ((bitWorkArea >> 8) & MASK_8BITS);
buffer[pos++] = (byte) ((bitWorkArea) & MASK_8BITS);
break;
default:
break;
}
}
}
/**
* Encodes binary data using the base64 algorithm but does not chunk the output.
*
@ -363,7 +390,7 @@ public class Base64 {
public static byte[] encodeBase64(byte[] binaryData) {
return encodeBase64(binaryData, false, false, Integer.MAX_VALUE);
}
/**
* Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
*
@ -380,24 +407,22 @@ public class Base64 {
if (binaryData == null || binaryData.length == 0) {
return binaryData;
}
// Create this so can use the super-class method
// Also ensures that the same roundings are performed by the ctor and the code
Base64 b64 = isChunked ? new Base64(MIME_CHUNK_SIZE, CHUNK_SEPARATOR, urlSafe) : new Base64(0, CHUNK_SEPARATOR,
urlSafe);
Base64 b64 = isChunked ? new Base64(MIME_CHUNK_SIZE, CHUNK_SEPARATOR, urlSafe)
: new Base64(0, CHUNK_SEPARATOR, urlSafe);
long len = b64.getEncodedLength(binaryData);
if (len > maxResultSize) {
throw new IllegalArgumentException("Input array too big, the output array would be bigger (" +
len +
") than the specified maximum size of " +
maxResultSize);
throw new IllegalArgumentException("Input array too big, the output array would be bigger (" + len
+ ") than the specified maximum size of " + maxResultSize);
}
return b64.encode(binaryData);
}
/**
* Decodes Base64 data into octets
* Decodes Base64 data into octets.
*
* @param base64Data Byte array containing Base64 data
* @return Array containing decoded data.
@ -405,7 +430,7 @@ public class Base64 {
public static byte[] decodeBase64(byte[] base64Data) {
return new Base64().decode(base64Data);
}
/**
* Returns whether or not the <code>octet</code> is in the Base32 alphabet.
*
@ -415,97 +440,93 @@ public class Base64 {
protected boolean isInAlphabet(byte octet) {
return octet >= 0 && octet < decodeTable.length && decodeTable[octet] != -1;
}
/**
* Below from base class
*/
/**
* MIME chunk size per RFC 2045 section 6.8.
* <p>
* <p> The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any
* equal signs. </p>
*
* <p> The {@value} character limit does not count the trailing CRLF, but counts all other characters, including
* any equal signs. </p>
*
* @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 6.8</a>
*/
private static final int MIME_CHUNK_SIZE = 76;
private static final int DEFAULT_BUFFER_RESIZE_FACTOR = 2;
/**
* Defines the default buffer size - currently {@value} - must be large enough for at least one encoded
* block+separator
* block+separator.
*/
private static final int DEFAULT_BUFFER_SIZE = 8192;
/**
* Mask used to extract 8 bits, used in decoding bytes
* Mask used to extract 8 bits, used in decoding bytes.
*/
private static final int MASK_8BITS = 0xff;
/**
* Byte used to pad output.
*/
private static final byte PAD_DEFAULT = '=';
private static final byte PAD = PAD_DEFAULT;
/**
* Number of bytes in each full block of unencoded data, e.g. 4 for Base64 and 5 for Base32
*/
private final int unencodedBlockSize;
/**
* Number of bytes in each full block of encoded data, e.g. 3 for Base64 and 8 for Base32
*/
private final int encodedBlockSize;
/**
* Chunksize for encoding. Not used when decoding. A value of zero or less implies no chunking of the encoded data.
* Rounded down to nearest multiple of encodedBlockSize.
*/
private final int lineLength;
/**
* Size of chunk separator. Not used unless {@link #lineLength} > 0.
*/
private final int chunkSeparatorLength;
/**
* Buffer for streaming.
*/
private byte[] buffer;
/**
* Position where next character should be written in the buffer.
*/
private int pos;
/**
* Position where next character should be read from the buffer.
*/
private int readPos;
/**
* Boolean flag to indicate the EOF has been reached. Once EOF has been reached, this object becomes useless, and
* must be thrown away.
*/
private boolean eof;
/**
* Variable tracks how many characters have been written to the current line. Only used when encoding. We use it to
* make sure each encoded line never goes beyond lineLength (if lineLength > 0).
*/
private int currentLinePos;
/**
* Writes to the buffer only occur after every 3/5 reads when encoding, and every 4/8 reads when decoding. This
* variable helps track that.
*/
private int modulus;
/**
* Ensure that the buffer has room for <code>size</code> bytes
* Ensure that the buffer has room for <code>size</code> bytes.
*
* @param size minimum spare space required
*/
@ -522,7 +543,7 @@ public class Base64 {
}
}
}
/**
* Extracts buffered data into the provided byte[] array, starting at position bPos, up to a maximum of bAvail
* bytes. Returns how many bytes were actually extracted.
@ -544,7 +565,7 @@ public class Base64 {
}
return eof ? -1 : 0;
}
/**
* Resets this object to its initial newly constructed state.
*/
@ -556,47 +577,11 @@ public class Base64 {
modulus = 0;
eof = false;
}
/**
* Decodes a byte[] containing characters in the Base-N alphabet.
*
* @param pArray A byte array containing Base-N character data
* @return a byte array containing binary data
*/
private byte[] decode(byte[] pArray) {
reset();
if (pArray == null || pArray.length == 0) {
return pArray;
}
decode(pArray, 0, pArray.length);
decode(pArray, 0, -1);
byte[] result = new byte[pos];
readResults(result, 0, result.length);
return result;
}
/**
* Encodes a byte[] containing binary data, into a byte[] containing characters in the alphabet.
*
* @param pArray a byte array containing binary data
* @return A byte array containing only the basen alphabetic character data
*/
private byte[] encode(byte[] pArray) {
reset();
if (pArray == null || pArray.length == 0) {
return pArray;
}
encode(pArray, 0, pArray.length);
encode(pArray, 0, -1);
byte[] buf = new byte[pos - readPos];
readResults(buf, 0, buf.length);
return buf;
}
/**
* Tests a given byte array to see if it contains any characters within the alphabet or PAD.
* <p>
* Intended for use in checking line-ending arrays
*
* <p>Intended for use in checking line-ending arrays
*
* @param arrayOctet byte array to test
* @return <code>true</code> if any byte is a valid character in the alphabet or PAD; <code>false</code> otherwise
@ -612,7 +597,7 @@ public class Base64 {
}
return false;
}
/**
* Calculates the amount of space needed to encode the supplied array.
*
@ -623,10 +608,10 @@ public class Base64 {
private long getEncodedLength(byte[] pArray) {
// Calculate non-chunked size - rounded up to allow for padding
// cast to long is needed to avoid possibility of overflow
long len = ((pArray.length + unencodedBlockSize - 1) / unencodedBlockSize) * (long)encodedBlockSize;
long len = ((pArray.length + unencodedBlockSize - 1) / unencodedBlockSize) * (long) encodedBlockSize;
if (lineLength > 0) {
/**
* Round up to nearest multiple
/*
Round up to nearest multiple
*/
len += ((len + lineLength - 1) / lineLength) * chunkSeparatorLength;
}

View File

@ -13,16 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.identify;
/**
* Credential Listener
* Credential Listener.
*
* @author Nacos
*/
public interface CredentialListener {
/**
* update Credential
* update Credential.
*/
void onUpdateCredential();
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.identify;
import com.alibaba.nacos.client.utils.LogUtils;
@ -22,21 +23,24 @@ import org.slf4j.Logger;
import java.util.concurrent.ConcurrentHashMap;
/**
* Credential Service
* Credential Service.
*
* @author Nacos
*/
public final class CredentialService implements SpasCredentialLoader {
private static final Logger LOGGER = LogUtils.logger(CredentialService.class);
private static ConcurrentHashMap<String, CredentialService> instances
= new ConcurrentHashMap<String, CredentialService>();
private String appName;
private static final ConcurrentHashMap<String, CredentialService> INSTANCES = new ConcurrentHashMap<String, CredentialService>();
private final String appName;
private Credentials credentials = new Credentials();
private CredentialWatcher watcher;
private final CredentialWatcher watcher;
private CredentialListener listener;
private CredentialService(String appName) {
if (appName == null) {
String value = System.getProperty("project.name");
@ -47,44 +51,53 @@ public final class CredentialService implements SpasCredentialLoader {
this.appName = appName;
watcher = new CredentialWatcher(appName, this);
}
public static CredentialService getInstance() {
return getInstance(null);
}
public static CredentialService getInstance(String appName) {
String key = appName != null ? appName : IdentifyConstants.NO_APP_NAME;
CredentialService instance = instances.get(key);
CredentialService instance = INSTANCES.get(key);
if (instance == null) {
instance = new CredentialService(appName);
CredentialService previous = instances.putIfAbsent(key, instance);
CredentialService previous = INSTANCES.putIfAbsent(key, instance);
if (previous != null) {
instance = previous;
}
}
return instance;
}
public static CredentialService freeInstance() {
return freeInstance(null);
}
/**
* Free instance.
*
* @param appName app name
* @return {@link CredentialService}
*/
public static CredentialService freeInstance(String appName) {
String key = appName != null ? appName : IdentifyConstants.NO_APP_NAME;
CredentialService instance = instances.remove(key);
CredentialService instance = INSTANCES.remove(key);
if (instance != null) {
instance.free();
}
return instance;
}
/**
* Free service.
*/
public void free() {
if (watcher != null) {
watcher.stop();
}
LOGGER.info("[{}] {} is freed", appName, this.getClass().getSimpleName());
}
@Override
public Credentials getCredential() {
Credentials localCredential = credentials;
@ -93,7 +106,7 @@ public final class CredentialService implements SpasCredentialLoader {
}
return credentials;
}
public void setCredential(Credentials credential) {
boolean changed = !(credentials == credential || (credentials != null && credentials.identical(credential)));
credentials = credential;
@ -101,36 +114,36 @@ public final class CredentialService implements SpasCredentialLoader {
listener.onUpdateCredential();
}
}
public void setStaticCredential(Credentials credential) {
if (watcher != null) {
watcher.stop();
}
setCredential(credential);
}
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

@ -13,46 +13,58 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.identify;
import com.alibaba.nacos.client.utils.LogUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import org.slf4j.Logger;
import java.io.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Properties;
import java.util.Timer;
import java.util.TimerTask;
/**
* Credential Watcher
* Credential Watcher.
*
* @author Nacos
*/
public class CredentialWatcher {
private static final Logger SpasLogger = LogUtils.logger(CredentialWatcher.class);
private static final Logger SPAS_LOGGER = LogUtils.logger(CredentialWatcher.class);
private static final long REFRESH_INTERVAL = 10 * 1000;
private CredentialService serviceInstance;
private String appName;
private final CredentialService serviceInstance;
private final String appName;
private String propertyPath;
private TimerTask watcher;
private final TimerTask watcher;
private boolean stopped;
@SuppressWarnings("PMD.AvoidUseTimerRule")
public CredentialWatcher(String appName, CredentialService serviceInstance) {
this.appName = appName;
this.serviceInstance = serviceInstance;
loadCredential(true);
watcher = new TimerTask() {
private Timer timer = new Timer(true);
private final Timer timer = new Timer(true);
private long modified = 0;
{
timer.schedule(this, REFRESH_INTERVAL, REFRESH_INTERVAL);
}
@Override
public void run() {
synchronized (this) {
@ -77,7 +89,10 @@ public class CredentialWatcher {
}
};
}
/**
* Stop watcher.
*/
public void stop() {
if (stopped) {
return;
@ -88,9 +103,9 @@ public class CredentialWatcher {
stopped = true;
}
}
SpasLogger.info("[{}] {} is stopped", appName, this.getClass().getSimpleName());
SPAS_LOGGER.info("[{}] {} is stopped", appName, this.getClass().getSimpleName());
}
private void loadCredential(boolean init) {
boolean logWarn = init;
if (propertyPath == null) {
@ -99,34 +114,35 @@ public class CredentialWatcher {
propertyPath = url.getPath();
}
if (propertyPath == null || propertyPath.isEmpty()) {
String value = System.getProperty("spas.identity");
if (StringUtils.isNotEmpty(value)) {
propertyPath = value;
}
if (propertyPath == null || propertyPath.isEmpty()) {
propertyPath = IdentifyConstants.CREDENTIAL_PATH + (appName == null ? IdentifyConstants.CREDENTIAL_DEFAULT
: appName);
propertyPath =
IdentifyConstants.CREDENTIAL_PATH + (appName == null ? IdentifyConstants.CREDENTIAL_DEFAULT
: appName);
} else {
if (logWarn) {
SpasLogger.info("[{}] Defined credential file: -Dspas.identity={}", appName, propertyPath);
SPAS_LOGGER.info("[{}] Defined credential file: -Dspas.identity={}", appName, propertyPath);
}
}
} else {
if (logWarn) {
SpasLogger.info("[{}] Load credential file from classpath: {}", appName,
IdentifyConstants.PROPERTIES_FILENAME);
SPAS_LOGGER.info("[{}] Load credential file from classpath: {}", appName,
IdentifyConstants.PROPERTIES_FILENAME);
}
}
}
InputStream propertiesIS = null;
do {
try {
propertiesIS = new FileInputStream(propertyPath);
} catch (FileNotFoundException e) {
if (appName != null && !appName.equals(IdentifyConstants.CREDENTIAL_DEFAULT) && propertyPath.equals(
IdentifyConstants.CREDENTIAL_PATH + appName)) {
if (appName != null && !appName.equals(IdentifyConstants.CREDENTIAL_DEFAULT) && propertyPath
.equals(IdentifyConstants.CREDENTIAL_PATH + appName)) {
propertyPath = IdentifyConstants.CREDENTIAL_PATH + IdentifyConstants.CREDENTIAL_DEFAULT;
continue;
}
@ -137,7 +153,7 @@ public class CredentialWatcher {
}
break;
} while (true);
String accessKey = null;
String secretKey = null;
String tenantId = null;
@ -147,7 +163,7 @@ public class CredentialWatcher {
secretKey = System.getenv(IdentifyConstants.ENV_SECRET_KEY);
if (accessKey == null && secretKey == null) {
if (logWarn) {
SpasLogger.info("{} No credential found", appName);
SPAS_LOGGER.info("{} No credential found", appName);
}
return;
}
@ -156,23 +172,23 @@ public class CredentialWatcher {
try {
properties.load(propertiesIS);
} catch (IOException e) {
SpasLogger.error("[26] Unable to load credential file, appName:" + appName
+ "Unable to load credential file " + propertyPath, e);
SPAS_LOGGER.error("[26] Unable to load credential file, appName:" + appName
+ "Unable to load credential file " + propertyPath, e);
propertyPath = null;
return;
} finally {
try {
propertiesIS.close();
} catch (IOException e) {
SpasLogger.error("[27] Unable to close credential file, appName:" + appName
+ "Unable to close credential file " + propertyPath, e);
SPAS_LOGGER.error("[27] Unable to close credential file, appName:" + appName
+ "Unable to close credential file " + propertyPath, e);
}
}
if (logWarn) {
SpasLogger.info("[{}] Load credential file {}", appName, propertyPath);
SPAS_LOGGER.info("[{}] Load credential file {}", appName, propertyPath);
}
if (!IdentifyConstants.DOCKER_CREDENTIAL_PATH.equals(propertyPath)) {
if (properties.containsKey(IdentifyConstants.ACCESS_KEY)) {
accessKey = properties.getProperty(IdentifyConstants.ACCESS_KEY);
@ -190,32 +206,33 @@ public class CredentialWatcher {
if (properties.containsKey(IdentifyConstants.DOCKER_SECRET_KEY)) {
secretKey = properties.getProperty(IdentifyConstants.DOCKER_SECRET_KEY);
}
if (properties.containsKey(IdentifyConstants.DOCKER_TENANT_ID)) {
tenantId = properties.getProperty(IdentifyConstants.DOCKER_TENANT_ID);
}
}
}
if (accessKey != null) {
accessKey = accessKey.trim();
}
if (secretKey != null) {
secretKey = secretKey.trim();
}
if (tenantId != null) {
tenantId = tenantId.trim();
}
Credentials credential = new Credentials(accessKey, secretKey, tenantId);
if (!credential.valid()) {
SpasLogger.warn("[1] Credential file missing required property {} Credential file missing {} or {}",
appName, IdentifyConstants.ACCESS_KEY, IdentifyConstants.SECRET_KEY);
SPAS_LOGGER
.warn("[1] Credential file missing required property {} Credential file missing {} or {}", appName,
IdentifyConstants.ACCESS_KEY, IdentifyConstants.SECRET_KEY);
propertyPath = null;
// return;
}
serviceInstance.setCredential(credential);
}
}

View File

@ -13,67 +13,72 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.identify;
/**
* Credentials
* Credentials.
*
* @author Nacos
*/
public class Credentials implements SpasCredential {
private volatile String accessKey;
private volatile String secretKey;
private volatile String tenantId;
public Credentials(String accessKey, String secretKey, String tenantId) {
this.accessKey = accessKey;
this.secretKey = secretKey;
this.tenantId = tenantId;
}
public Credentials() {
this(null, null, null);
}
@Override
public String getAccessKey() {
return accessKey;
}
public void setAccessKey(String accessKey) {
this.accessKey = accessKey;
}
@Override
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public String getTenantId() {
return tenantId;
}
public void setTenantId(String tenantId) {
this.tenantId = tenantId;
}
public boolean valid() {
return accessKey != null && !accessKey.isEmpty() && secretKey != null
&& !secretKey.isEmpty();
return accessKey != null && !accessKey.isEmpty() && secretKey != null && !secretKey.isEmpty();
}
/**
* Identical.
*
* @param other other
* @return true if identical
*/
public boolean identical(Credentials other) {
return this == other || (other != null
&& (accessKey == null && other.accessKey == null
|| accessKey != null && accessKey.equals(other.accessKey))
&& (secretKey == null && other.secretKey == null
|| secretKey != null && secretKey.equals(other.secretKey)));
return this == other || (other != null && (accessKey == null && other.accessKey == null
|| accessKey != null && accessKey.equals(other.accessKey)) && (
secretKey == null && other.secretKey == null || secretKey != null && secretKey
.equals(other.secretKey)));
}
}

View File

@ -13,40 +13,42 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.identify;
/**
* Identify Constants
* Identify Constants.
*
* @author Nacos
*/
public class IdentifyConstants {
public static final String ACCESS_KEY = "accessKey";
public static final String SECRET_KEY = "secretKey";
public static final String TENANT_ID = "tenantId";
public static final String PROPERTIES_FILENAME = "spas.properties";
public static final String CREDENTIAL_PATH = "/home/admin/.spas_key/";
public static final String CREDENTIAL_DEFAULT = "default";
public static final String DOCKER_CREDENTIAL_PATH = "/etc/instanceInfo";
public static final String DOCKER_ACCESS_KEY = "env_spas_accessKey";
public static final String DOCKER_SECRET_KEY = "env_spas_secretKey";
public static final String DOCKER_TENANT_ID = "ebv_spas_tenantId";
public static final String ENV_ACCESS_KEY = "spas_accessKey";
public static final String ENV_SECRET_KEY = "spas_secretKey";
public static final String ENV_TENANT_ID = "tenant.id";
public static final String NO_APP_NAME = "";
}

View File

@ -13,23 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.identify;
/**
* Spas Credential Interface
* Spas Credential Interface.
*
* @author Nacos
*/
public interface SpasCredential {
/**
* get AccessKey
* get AccessKey.
*
* @return AccessKey
*/
String getAccessKey();
/**
* get SecretKey
* get SecretKey.
*
* @return SecretKey
*/

View File

@ -13,16 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.identify;
/**
* Spas Credential Loader
* Spas Credential Loader.
*
* @author Nacos
*/
public interface SpasCredentialLoader {
/**
* get Credential
* get Credential.
*
* @return Credential
*/

View File

@ -13,116 +13,121 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.identify;
package com.alibaba.nacos.client.identify;
import com.alibaba.nacos.common.utils.StringUtils;
/**
* Sts config
* Sts config.
*
* @author Nacos
*/
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
public class STSConfig {
private static final String RAM_SECURITY_CREDENTIALS_URL
= "http://100.100.100.200/latest/meta-data/ram/security-credentials/";
public class StsConfig {
private static final String RAM_SECURITY_CREDENTIALS_URL = "http://100.100.100.200/latest/meta-data/ram/security-credentials/";
private String ramRoleName;
/**
* STS 临时凭证有效期剩余多少时开始刷新允许本地时间比 STS 服务时间最多慢多久
* STS 临时凭证有效期剩余多少时开始刷新允许本地时间比 STS 服务时间最多慢多久.
*/
private int timeToRefreshInMillisecond = 3 * 60 * 1000;
/**
* 获取 STS 临时凭证的元数据接口包含角色名称
* 获取 STS 临时凭证的元数据接口包含角色名称.
*/
private String securityCredentialsUrl;
/**
* 设定 STS 临时凭证不再通过元数据接口获取
* 设定 STS 临时凭证不再通过元数据接口获取.
*/
private String securityCredentials;
/**
* 是否缓存
* 是否缓存.
*/
private boolean cacheSecurityCredentials = true;
private static class Singleton {
private static final STSConfig INSTANCE = new STSConfig();
private static final StsConfig INSTANCE = new StsConfig();
}
private STSConfig() {
private StsConfig() {
String ramRoleName = System.getProperty("ram.role.name");
if (!StringUtils.isBlank(ramRoleName)) {
setRamRoleName(ramRoleName);
}
String timeToRefreshInMillisecond = System.getProperty("time.to.refresh.in.millisecond");
if (!StringUtils.isBlank(timeToRefreshInMillisecond)) {
setTimeToRefreshInMillisecond(Integer.parseInt(timeToRefreshInMillisecond));
}
String securityCredentials = System.getProperty("security.credentials");
if (!StringUtils.isBlank(securityCredentials)) {
setSecurityCredentials(securityCredentials);
}
String securityCredentialsUrl = System.getProperty("security.credentials.url");
if (!StringUtils.isBlank(securityCredentialsUrl)) {
setSecurityCredentialsUrl(securityCredentialsUrl);
}
String cacheSecurityCredentials = System.getProperty("cache.security.credentials");
if (!StringUtils.isBlank(cacheSecurityCredentials)) {
setCacheSecurityCredentials(Boolean.parseBoolean(cacheSecurityCredentials));
}
}
public static STSConfig getInstance() {
public static StsConfig getInstance() {
return Singleton.INSTANCE;
}
public String getRamRoleName() {
return ramRoleName;
}
public void setRamRoleName(String ramRoleName) {
this.ramRoleName = ramRoleName;
}
public int getTimeToRefreshInMillisecond() {
return timeToRefreshInMillisecond;
}
public void setTimeToRefreshInMillisecond(int timeToRefreshInMillisecond) {
this.timeToRefreshInMillisecond = timeToRefreshInMillisecond;
}
public String getSecurityCredentialsUrl() {
if (securityCredentialsUrl == null && ramRoleName != null) {
return RAM_SECURITY_CREDENTIALS_URL + ramRoleName;
}
return securityCredentialsUrl;
}
public void setSecurityCredentialsUrl(String securityCredentialsUrl) {
this.securityCredentialsUrl = securityCredentialsUrl;
}
public String getSecurityCredentials() {
return securityCredentials;
}
public void setSecurityCredentials(String securityCredentials) {
this.securityCredentials = securityCredentials;
}
public boolean isSTSOn() {
public boolean isStsOn() {
return StringUtils.isNotEmpty(getSecurityCredentials()) || StringUtils.isNotEmpty(getSecurityCredentialsUrl());
}
public boolean isCacheSecurityCredentials() {
return cacheSecurityCredentials;
}
public void setCacheSecurityCredentials(boolean cacheSecurityCredentials) {
this.cacheSecurityCredentials = cacheSecurityCredentials;
}

View File

@ -13,24 +13,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logging;
package com.alibaba.nacos.client.logging;
import com.alibaba.nacos.common.utils.ConvertUtils;
import com.alibaba.nacos.common.utils.StringUtils;
/**
* Abstract nacos logging.
*
* @author <a href="mailto:huangxiaoyu1018@gmail.com">hxy1991</a>
* @since 0.9.0
*/
public abstract class AbstractNacosLogging {
private static final String NACOS_LOGGING_CONFIG_PROPERTY = "nacos.logging.config";
private static final String NACOS_LOGGING_DEFAULT_CONFIG_ENABLED_PROPERTY = "nacos.logging.default.config.enabled";
private static final String NACOS_LOGGING_PATH_PROPERTY = "nacos.logging.path";
static {
String loggingPath = System.getProperty(NACOS_LOGGING_PATH_PROPERTY);
if (StringUtils.isBlank(loggingPath)) {
@ -38,7 +40,7 @@ public abstract class AbstractNacosLogging {
System.setProperty(NACOS_LOGGING_PATH_PROPERTY, userHome + "/logs/nacos");
}
}
protected String getLocation(String defaultLocation) {
String location = System.getProperty(NACOS_LOGGING_CONFIG_PROPERTY);
if (StringUtils.isBlank(location)) {
@ -49,15 +51,15 @@ public abstract class AbstractNacosLogging {
}
return location;
}
private boolean isDefaultConfigEnabled() {
String property = System.getProperty(NACOS_LOGGING_DEFAULT_CONFIG_ENABLED_PROPERTY);
// The default value is true.
return property == null || ConvertUtils.toBoolean(property);
}
/**
* Load logging configuration
* Load logging configuration.
*/
public abstract void loadConfiguration();
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logging.log4j2;
import com.alibaba.nacos.client.logging.AbstractNacosLogging;
@ -37,27 +38,27 @@ import java.util.Map;
* @since 0.9.0
*/
public class Log4J2NacosLogging extends AbstractNacosLogging {
private static final String NACOS_LOG4J2_LOCATION = "classpath:nacos-log4j2.xml";
private static final String FILE_PROTOCOL = "file";
private static final String NACOS_LOGGER_PREFIX = "com.alibaba.nacos";
private String location = getLocation(NACOS_LOG4J2_LOCATION);
private final String location = getLocation(NACOS_LOG4J2_LOCATION);
@Override
public void loadConfiguration() {
final LoggerContext loggerContext = (LoggerContext)LogManager.getContext(false);
final LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false);
final Configuration contextConfiguration = loggerContext.getConfiguration();
// load and start nacos configuration
Configuration configuration = loadConfiguration(loggerContext, location);
configuration.start();
// append loggers and appenders to contextConfiguration
Map<String, Appender> appenders = configuration.getAppenders();
for (Appender appender: appenders.values()) {
for (Appender appender : appenders.values()) {
contextConfiguration.addAppender(appender);
}
Map<String, LoggerConfig> loggers = configuration.getLoggers();
@ -66,10 +67,10 @@ public class Log4J2NacosLogging extends AbstractNacosLogging {
contextConfiguration.addLogger(name, loggers.get(name));
}
}
loggerContext.updateLoggers();
}
private Configuration loadConfiguration(LoggerContext loggerContext, String location) {
try {
URL url = ResourceUtils.getResourceUrl(location);
@ -77,11 +78,10 @@ public class Log4J2NacosLogging extends AbstractNacosLogging {
// since log4j 2.7 getConfiguration(LoggerContext loggerContext, ConfigurationSource source)
return ConfigurationFactory.getInstance().getConfiguration(loggerContext, source);
} catch (Exception e) {
throw new IllegalStateException(
"Could not initialize Log4J2 logging from " + location, e);
throw new IllegalStateException("Could not initialize Log4J2 logging from " + location, e);
}
}
private ConfigurationSource getConfigurationSource(URL url) throws IOException {
InputStream stream = url.openStream();
if (FILE_PROTOCOL.equals(url.getProtocol())) {

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logging.logback;
import ch.qos.logback.classic.LoggerContext;
@ -29,22 +30,22 @@ import org.slf4j.impl.StaticLoggerBinder;
* @since 0.9.0
*/
public class LogbackNacosLogging extends AbstractNacosLogging {
private static final String NACOS_LOGBACK_LOCATION = "classpath:nacos-logback.xml";
@Override
public void loadConfiguration() {
String location = getLocation(NACOS_LOGBACK_LOCATION);
if (StringUtils.isBlank(location)) {
return;
}
try {
LoggerContext loggerContext = (LoggerContext)StaticLoggerBinder.getSingleton().getLoggerFactory();
LoggerContext loggerContext = (LoggerContext) StaticLoggerBinder.getSingleton().getLoggerFactory();
new ContextInitializer(loggerContext).configureByResource(ResourceUtils.getResourceUrl(location));
} catch (Exception e) {
throw new IllegalStateException("Could not initialize Logback Nacos logging from " + location, e);
}
}
}

View File

@ -13,44 +13,44 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.monitor;
import io.prometheus.client.Gauge;
import io.prometheus.client.Histogram;
/**
* Metrics Monitor
* Metrics Monitor.
*
* @author Nacos
*/
public class MetricsMonitor {
private static Gauge nacosMonitor = Gauge.build()
.name("nacos_monitor").labelNames("module", "name")
.help("nacos_monitor").register();
private static Histogram nacosClientRequestHistogram = Histogram.build().labelNames("module", "method", "url", "code")
.name("nacos_client_request").help("nacos_client_request")
.register();
private static final Gauge NACOS_MONITOR = Gauge.build().name("nacos_monitor").labelNames("module", "name")
.help("nacos_monitor").register();
private static final Histogram NACOS_CLIENT_REQUEST_HISTOGRAM = Histogram.build()
.labelNames("module", "method", "url", "code").name("nacos_client_request").help("nacos_client_request")
.register();
public static Gauge.Child getServiceInfoMapSizeMonitor() {
return nacosMonitor.labels("naming", "serviceInfoMapSize");
return NACOS_MONITOR.labels("naming", "serviceInfoMapSize");
}
public static Gauge.Child getDom2BeatSizeMonitor() {
return nacosMonitor.labels("naming", "dom2BeatSize");
return NACOS_MONITOR.labels("naming", "dom2BeatSize");
}
public static Gauge.Child getListenConfigCountMonitor() {
return nacosMonitor.labels("naming", "listenConfigCount");
return NACOS_MONITOR.labels("naming", "listenConfigCount");
}
public static Histogram.Timer getConfigRequestMonitor(String method, String url, String code) {
return nacosClientRequestHistogram.labels("config", method, url, code).startTimer();
return NACOS_CLIENT_REQUEST_HISTOGRAM.labels("config", method, url, code).startTimer();
}
public static Histogram.Child getNamingRequestMonitor(String method, String url, String code) {
return nacosClientRequestHistogram.labels("naming", method, url, code);
return NACOS_CLIENT_REQUEST_HISTOGRAM.labels("naming", method, url, code);
}
}

View File

@ -34,31 +34,33 @@ import java.util.Map;
import java.util.Properties;
/**
* Nacos naming maintain service.
*
* @author liaochuntao
* @since 1.0.1
*/
@SuppressWarnings("PMD.ServiceOrDaoClassShouldEndWithImplRule")
public class NacosNamingMaintainService implements NamingMaintainService {
private String namespace;
private String endpoint;
private String serverList;
private NamingProxy serverProxy;
public NacosNamingMaintainService(String serverList) throws NacosException {
public NacosNamingMaintainService(String serverList) throws NacosException {
Properties properties = new Properties();
properties.setProperty(PropertyKeyConst.SERVER_ADDR, serverList);
init(properties);
}
public NacosNamingMaintainService(Properties properties) throws NacosException {
public NacosNamingMaintainService(Properties properties) throws NacosException {
init(properties);
}
private void init(Properties properties) throws NacosException {
private void init(Properties properties) throws NacosException {
ValidatorUtils.checkInitParam(properties);
namespace = InitUtils.initNamespaceForNaming(properties);
InitUtils.initSerialization();
@ -66,7 +68,7 @@ public class NacosNamingMaintainService implements NamingMaintainService {
InitUtils.initWebRootContext();
serverProxy = new NamingProxy(namespace, endpoint, serverList, properties);
}
private void initServerAddr(Properties properties) {
serverList = properties.getProperty(PropertyKeyConst.SERVER_ADDR);
endpoint = InitUtils.initEndpoint(properties);
@ -74,100 +76,101 @@ public class NacosNamingMaintainService implements NamingMaintainService {
serverList = "";
}
}
@Override
public void updateInstance(String serviceName, Instance instance) throws NacosException {
updateInstance(serviceName, Constants.DEFAULT_GROUP, instance);
}
@Override
public void updateInstance(String serviceName, String groupName, Instance instance) throws NacosException {
serverProxy.updateInstance(serviceName, groupName, instance);
}
@Override
public Service queryService(String serviceName) throws NacosException {
return queryService(serviceName, Constants.DEFAULT_GROUP);
}
@Override
public Service queryService(String serviceName, String groupName) throws NacosException {
return serverProxy.queryService(serviceName, groupName);
}
@Override
public void createService(String serviceName) throws NacosException {
createService(serviceName, Constants.DEFAULT_GROUP);
}
@Override
public void createService(String serviceName, String groupName) throws NacosException {
createService(serviceName, groupName, Constants.DEFAULT_PROTECT_THRESHOLD);
}
@Override
public void createService(String serviceName, String groupName, float protectThreshold) throws NacosException {
NoneSelector selector = new NoneSelector();
Service service = new Service();
service.setName(serviceName);
service.setGroupName(groupName);
service.setProtectThreshold(protectThreshold);
createService(service, selector);
createService(service, new NoneSelector());
}
@Override
public void createService(String serviceName, String groupName, float protectThreshold, String expression) throws NacosException {
public void createService(String serviceName, String groupName, float protectThreshold, String expression)
throws NacosException {
Service service = new Service();
service.setName(serviceName);
service.setGroupName(groupName);
service.setProtectThreshold(protectThreshold);
ExpressionSelector selector = new ExpressionSelector();
selector.setExpression(expression);
createService(service, selector);
}
@Override
public void createService(Service service, AbstractSelector selector) throws NacosException {
serverProxy.createService(service, selector);
}
@Override
public boolean deleteService(String serviceName) throws NacosException {
return deleteService(serviceName, Constants.DEFAULT_GROUP);
}
@Override
public boolean deleteService(String serviceName, String groupName) throws NacosException {
return serverProxy.deleteService(serviceName, groupName);
}
@Override
public void updateService(String serviceName, String groupName, float protectThreshold) throws NacosException {
Service service = new Service();
service.setName(serviceName);
service.setGroupName(groupName);
service.setProtectThreshold(protectThreshold);
updateService(service, new NoneSelector());
}
@Override
public void updateService(String serviceName, String groupName, float protectThreshold, Map<String, String> metadata) throws NacosException {
public void updateService(String serviceName, String groupName, float protectThreshold,
Map<String, String> metadata) throws NacosException {
Service service = new Service();
service.setName(serviceName);
service.setGroupName(groupName);
service.setProtectThreshold(protectThreshold);
service.setMetadata(metadata);
updateService(service, new NoneSelector());
}
@Override
public void updateService(Service service, AbstractSelector selector) throws NacosException {
serverProxy.updateService(service, selector);
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming;
import com.alibaba.nacos.api.PropertyKeyConst;
@ -44,45 +45,45 @@ import java.util.List;
import java.util.Properties;
/**
* Nacos Naming Service
* Nacos Naming Service.
*
* @author nkorange
*/
@SuppressWarnings("PMD.ServiceOrDaoClassShouldEndWithImplRule")
public class NacosNamingService implements NamingService {
/**
* Each Naming service should have different namespace.
*/
private String namespace;
private String endpoint;
private String serverList;
private String cacheDir;
private String logName;
private HostReactor hostReactor;
private BeatReactor beatReactor;
private EventDispatcher eventDispatcher;
private NamingProxy serverProxy;
public NacosNamingService(String serverList) throws NacosException {
Properties properties = new Properties();
properties.setProperty(PropertyKeyConst.SERVER_ADDR, serverList);
init(properties);
}
public NacosNamingService(Properties properties) throws NacosException {
public NacosNamingService(Properties properties) throws NacosException {
init(properties);
}
private void init(Properties properties) throws NacosException {
private void init(Properties properties) throws NacosException {
ValidatorUtils.checkInitParam(properties);
this.namespace = InitUtils.initNamespaceForNaming(properties);
InitUtils.initSerialization();
@ -90,43 +91,44 @@ public class NacosNamingService implements NamingService {
InitUtils.initWebRootContext();
initCacheDir();
initLogName(properties);
this.eventDispatcher = new EventDispatcher();
this.serverProxy = new NamingProxy(this.namespace, this.endpoint, this.serverList, properties);
this.beatReactor = new BeatReactor(this.serverProxy, initClientBeatThreadCount(properties));
this.hostReactor = new HostReactor(this.eventDispatcher, this.serverProxy, beatReactor, this.cacheDir,
isLoadCacheAtStart(properties), initPollingThreadCount(properties));
isLoadCacheAtStart(properties), initPollingThreadCount(properties));
}
private int initClientBeatThreadCount(Properties properties) {
if (properties == null) {
return UtilAndComs.DEFAULT_CLIENT_BEAT_THREAD_COUNT;
}
return ConvertUtils.toInt(properties.getProperty(PropertyKeyConst.NAMING_CLIENT_BEAT_THREAD_COUNT),
UtilAndComs.DEFAULT_CLIENT_BEAT_THREAD_COUNT);
UtilAndComs.DEFAULT_CLIENT_BEAT_THREAD_COUNT);
}
private int initPollingThreadCount(Properties properties) {
if (properties == null) {
return UtilAndComs.DEFAULT_POLLING_THREAD_COUNT;
}
return ConvertUtils.toInt(properties.getProperty(PropertyKeyConst.NAMING_POLLING_THREAD_COUNT),
UtilAndComs.DEFAULT_POLLING_THREAD_COUNT);
UtilAndComs.DEFAULT_POLLING_THREAD_COUNT);
}
private boolean isLoadCacheAtStart(Properties properties) {
boolean loadCacheAtStart = false;
if (properties != null && StringUtils.isNotEmpty(properties.getProperty(PropertyKeyConst.NAMING_LOAD_CACHE_AT_START))) {
loadCacheAtStart = ConvertUtils.toBoolean(
properties.getProperty(PropertyKeyConst.NAMING_LOAD_CACHE_AT_START));
if (properties != null && StringUtils
.isNotEmpty(properties.getProperty(PropertyKeyConst.NAMING_LOAD_CACHE_AT_START))) {
loadCacheAtStart = ConvertUtils
.toBoolean(properties.getProperty(PropertyKeyConst.NAMING_LOAD_CACHE_AT_START));
}
return loadCacheAtStart;
}
private void initServerAddr(Properties properties) {
serverList = properties.getProperty(PropertyKeyConst.SERVER_ADDR);
endpoint = InitUtils.initEndpoint(properties);
@ -134,149 +136,160 @@ public class NacosNamingService implements NamingService {
serverList = "";
}
}
private void initLogName(Properties properties) {
logName = System.getProperty(UtilAndComs.NACOS_NAMING_LOG_NAME);
if (StringUtils.isEmpty(logName)) {
if (properties != null && StringUtils.isNotEmpty(properties.getProperty(UtilAndComs.NACOS_NAMING_LOG_NAME))) {
if (properties != null && StringUtils
.isNotEmpty(properties.getProperty(UtilAndComs.NACOS_NAMING_LOG_NAME))) {
logName = properties.getProperty(UtilAndComs.NACOS_NAMING_LOG_NAME);
} else {
logName = "naming.log";
}
}
}
private void initCacheDir() {
cacheDir = System.getProperty("com.alibaba.nacos.naming.cache.dir");
if (StringUtils.isEmpty(cacheDir)) {
cacheDir = System.getProperty("user.home") + "/nacos/naming/" + namespace;
}
}
@Override
public void registerInstance(String serviceName, String ip, int port) throws NacosException {
registerInstance(serviceName, ip, port, Constants.DEFAULT_CLUSTER_NAME);
}
@Override
public void registerInstance(String serviceName, String groupName, String ip, int port) throws NacosException {
registerInstance(serviceName, groupName, ip, port, Constants.DEFAULT_CLUSTER_NAME);
}
@Override
public void registerInstance(String serviceName, String ip, int port, String clusterName) throws NacosException {
registerInstance(serviceName, Constants.DEFAULT_GROUP, ip, port, clusterName);
}
@Override
public void registerInstance(String serviceName, String groupName, String ip, int port, String clusterName) throws NacosException {
public void registerInstance(String serviceName, String groupName, String ip, int port, String clusterName)
throws NacosException {
Instance instance = new Instance();
instance.setIp(ip);
instance.setPort(port);
instance.setWeight(1.0);
instance.setClusterName(clusterName);
registerInstance(serviceName, groupName, instance);
}
@Override
public void registerInstance(String serviceName, Instance instance) throws NacosException {
registerInstance(serviceName, Constants.DEFAULT_GROUP, instance);
}
@Override
public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
String groupedServiceName = NamingUtils.getGroupedName(serviceName, groupName);
if (instance.isEphemeral()) {
BeatInfo beatInfo = beatReactor.buildBeatInfo(instance);
beatReactor.addBeatInfo(NamingUtils.getGroupedName(serviceName, groupName), beatInfo);
BeatInfo beatInfo = beatReactor.buildBeatInfo(groupedServiceName, instance);
beatReactor.addBeatInfo(groupedServiceName, beatInfo);
}
serverProxy.registerService(NamingUtils.getGroupedName(serviceName, groupName), groupName, instance);
serverProxy.registerService(groupedServiceName, groupName, instance);
}
@Override
public void deregisterInstance(String serviceName, String ip, int port) throws NacosException {
deregisterInstance(serviceName, ip, port, Constants.DEFAULT_CLUSTER_NAME);
}
@Override
public void deregisterInstance(String serviceName, String groupName, String ip, int port) throws NacosException {
deregisterInstance(serviceName, groupName, ip, port, Constants.DEFAULT_CLUSTER_NAME);
}
@Override
public void deregisterInstance(String serviceName, String ip, int port, String clusterName) throws NacosException {
deregisterInstance(serviceName, Constants.DEFAULT_GROUP, ip, port, clusterName);
}
@Override
public void deregisterInstance(String serviceName, String groupName, String ip, int port, String clusterName) throws NacosException {
public void deregisterInstance(String serviceName, String groupName, String ip, int port, String clusterName)
throws NacosException {
Instance instance = new Instance();
instance.setIp(ip);
instance.setPort(port);
instance.setClusterName(clusterName);
deregisterInstance(serviceName, groupName, instance);
}
@Override
public void deregisterInstance(String serviceName, Instance instance) throws NacosException {
deregisterInstance(serviceName, Constants.DEFAULT_GROUP, instance);
}
@Override
public void deregisterInstance(String serviceName, String groupName, Instance instance) throws NacosException {
if (instance.isEphemeral()) {
beatReactor.removeBeatInfo(NamingUtils.getGroupedName(serviceName, groupName), instance.getIp(), instance.getPort());
beatReactor.removeBeatInfo(NamingUtils.getGroupedName(serviceName, groupName), instance.getIp(),
instance.getPort());
}
serverProxy.deregisterService(NamingUtils.getGroupedName(serviceName, groupName), instance);
}
@Override
public List<Instance> getAllInstances(String serviceName) throws NacosException {
return getAllInstances(serviceName, new ArrayList<String>());
}
@Override
public List<Instance> getAllInstances(String serviceName, String groupName) throws NacosException {
return getAllInstances(serviceName, groupName, new ArrayList<String>());
}
@Override
public List<Instance> getAllInstances(String serviceName, boolean subscribe) throws NacosException {
return getAllInstances(serviceName, new ArrayList<String>(), subscribe);
}
@Override
public List<Instance> getAllInstances(String serviceName, String groupName, boolean subscribe) throws NacosException {
public List<Instance> getAllInstances(String serviceName, String groupName, boolean subscribe)
throws NacosException {
return getAllInstances(serviceName, groupName, new ArrayList<String>(), subscribe);
}
@Override
public List<Instance> getAllInstances(String serviceName, List<String> clusters) throws NacosException {
return getAllInstances(serviceName, clusters, true);
}
@Override
public List<Instance> getAllInstances(String serviceName, String groupName, List<String> clusters) throws NacosException {
public List<Instance> getAllInstances(String serviceName, String groupName, List<String> clusters)
throws NacosException {
return getAllInstances(serviceName, groupName, clusters, true);
}
@Override
public List<Instance> getAllInstances(String serviceName, List<String> clusters, boolean subscribe)
throws NacosException {
throws NacosException {
return getAllInstances(serviceName, Constants.DEFAULT_GROUP, clusters, subscribe);
}
@Override
public List<Instance> getAllInstances(String serviceName, String groupName, List<String> clusters, boolean subscribe) throws NacosException {
public List<Instance> getAllInstances(String serviceName, String groupName, List<String> clusters,
boolean subscribe) throws NacosException {
ServiceInfo serviceInfo;
if (subscribe) {
serviceInfo = hostReactor.getServiceInfo(NamingUtils.getGroupedName(serviceName, groupName), StringUtils.join(clusters, ","));
serviceInfo = hostReactor.getServiceInfo(NamingUtils.getGroupedName(serviceName, groupName),
StringUtils.join(clusters, ","));
} else {
serviceInfo = hostReactor.getServiceInfoDirectlyFromServer(NamingUtils.getGroupedName(serviceName, groupName), StringUtils.join(clusters, ","));
serviceInfo = hostReactor
.getServiceInfoDirectlyFromServer(NamingUtils.getGroupedName(serviceName, groupName),
StringUtils.join(clusters, ","));
}
List<Instance> list;
if (serviceInfo == null || CollectionUtils.isEmpty(list = serviceInfo.getHosts())) {
@ -284,183 +297,69 @@ public class NacosNamingService implements NamingService {
}
return list;
}
@Override
public List<Instance> selectInstances(String serviceName, boolean healthy) throws NacosException {
return selectInstances(serviceName, new ArrayList<String>(), healthy);
}
@Override
public List<Instance> selectInstances(String serviceName, String groupName, boolean healthy) throws NacosException {
return selectInstances(serviceName, groupName, healthy, true);
}
@Override
public List<Instance> selectInstances(String serviceName, boolean healthy, boolean subscribe)
throws NacosException {
throws NacosException {
return selectInstances(serviceName, new ArrayList<String>(), healthy, subscribe);
}
@Override
public List<Instance> selectInstances(String serviceName, String groupName, boolean healthy, boolean subscribe) throws NacosException {
public List<Instance> selectInstances(String serviceName, String groupName, boolean healthy, boolean subscribe)
throws NacosException {
return selectInstances(serviceName, groupName, new ArrayList<String>(), healthy, subscribe);
}
@Override
public List<Instance> selectInstances(String serviceName, List<String> clusters, boolean healthy)
throws NacosException {
throws NacosException {
return selectInstances(serviceName, clusters, healthy, true);
}
@Override
public List<Instance> selectInstances(String serviceName, String groupName, List<String> clusters, boolean healthy) throws NacosException {
public List<Instance> selectInstances(String serviceName, String groupName, List<String> clusters, boolean healthy)
throws NacosException {
return selectInstances(serviceName, groupName, clusters, healthy, true);
}
@Override
public List<Instance> selectInstances(String serviceName, List<String> clusters, boolean healthy,
boolean subscribe) throws NacosException {
public List<Instance> selectInstances(String serviceName, List<String> clusters, boolean healthy, boolean subscribe)
throws NacosException {
return selectInstances(serviceName, Constants.DEFAULT_GROUP, clusters, healthy, subscribe);
}
@Override
public List<Instance> selectInstances(String serviceName, String groupName, List<String> clusters, boolean healthy, boolean subscribe) throws NacosException {
public List<Instance> selectInstances(String serviceName, String groupName, List<String> clusters, boolean healthy,
boolean subscribe) throws NacosException {
ServiceInfo serviceInfo;
if (subscribe) {
serviceInfo = hostReactor.getServiceInfo(NamingUtils.getGroupedName(serviceName, groupName), StringUtils.join(clusters, ","));
serviceInfo = hostReactor.getServiceInfo(NamingUtils.getGroupedName(serviceName, groupName),
StringUtils.join(clusters, ","));
} else {
serviceInfo = hostReactor.getServiceInfoDirectlyFromServer(NamingUtils.getGroupedName(serviceName, groupName), StringUtils.join(clusters, ","));
serviceInfo = hostReactor
.getServiceInfoDirectlyFromServer(NamingUtils.getGroupedName(serviceName, groupName),
StringUtils.join(clusters, ","));
}
return selectInstances(serviceInfo, healthy);
}
@Override
public Instance selectOneHealthyInstance(String serviceName) throws NacosException {
return selectOneHealthyInstance(serviceName, new ArrayList<String>());
}
@Override
public Instance selectOneHealthyInstance(String serviceName, String groupName) throws NacosException {
return selectOneHealthyInstance(serviceName, groupName, true);
}
@Override
public Instance selectOneHealthyInstance(String serviceName, boolean subscribe) throws NacosException {
return selectOneHealthyInstance(serviceName, new ArrayList<String>(), subscribe);
}
@Override
public Instance selectOneHealthyInstance(String serviceName, String groupName, boolean subscribe) throws NacosException {
return selectOneHealthyInstance(serviceName, groupName, new ArrayList<String>(), subscribe);
}
@Override
public Instance selectOneHealthyInstance(String serviceName, List<String> clusters) throws NacosException {
return selectOneHealthyInstance(serviceName, clusters, true);
}
@Override
public Instance selectOneHealthyInstance(String serviceName, String groupName, List<String> clusters) throws NacosException {
return selectOneHealthyInstance(serviceName, groupName, clusters, true);
}
@Override
public Instance selectOneHealthyInstance(String serviceName, List<String> clusters, boolean subscribe)
throws NacosException {
return selectOneHealthyInstance(serviceName, Constants.DEFAULT_GROUP, clusters, subscribe);
}
@Override
public Instance selectOneHealthyInstance(String serviceName, String groupName, List<String> clusters, boolean subscribe) throws NacosException {
if (subscribe) {
return Balancer.RandomByWeight.selectHost(
hostReactor.getServiceInfo(NamingUtils.getGroupedName(serviceName, groupName), StringUtils.join(clusters, ",")));
} else {
return Balancer.RandomByWeight.selectHost(
hostReactor.getServiceInfoDirectlyFromServer(NamingUtils.getGroupedName(serviceName, groupName), StringUtils.join(clusters, ",")));
}
}
@Override
public void subscribe(String serviceName, EventListener listener) throws NacosException {
subscribe(serviceName, new ArrayList<String>(), listener);
}
@Override
public void subscribe(String serviceName, String groupName, EventListener listener) throws NacosException {
subscribe(serviceName, groupName, new ArrayList<String>(), listener);
}
@Override
public void subscribe(String serviceName, List<String> clusters, EventListener listener) throws NacosException {
subscribe(serviceName, Constants.DEFAULT_GROUP, clusters, listener);
}
@Override
public void subscribe(String serviceName, String groupName, List<String> clusters, EventListener listener) throws NacosException {
eventDispatcher.addListener(hostReactor.getServiceInfo(NamingUtils.getGroupedName(serviceName, groupName),
StringUtils.join(clusters, ",")), StringUtils.join(clusters, ","), listener);
}
@Override
public void unsubscribe(String serviceName, EventListener listener) throws NacosException {
unsubscribe(serviceName, new ArrayList<String>(), listener);
}
@Override
public void unsubscribe(String serviceName, String groupName, EventListener listener) throws NacosException {
unsubscribe(serviceName, groupName, new ArrayList<String>(), listener);
}
@Override
public void unsubscribe(String serviceName, List<String> clusters, EventListener listener) throws NacosException {
unsubscribe(serviceName, Constants.DEFAULT_GROUP, clusters, listener);
}
@Override
public void unsubscribe(String serviceName, String groupName, List<String> clusters, EventListener listener) throws NacosException {
eventDispatcher.removeListener(NamingUtils.getGroupedName(serviceName, groupName), StringUtils.join(clusters, ","), listener);
}
@Override
public ListView<String> getServicesOfServer(int pageNo, int pageSize) throws NacosException {
return serverProxy.getServiceList(pageNo, pageSize, Constants.DEFAULT_GROUP);
}
@Override
public ListView<String> getServicesOfServer(int pageNo, int pageSize, String groupName) throws NacosException {
return getServicesOfServer(pageNo, pageSize, groupName, null);
}
@Override
public ListView<String> getServicesOfServer(int pageNo, int pageSize, AbstractSelector selector)
throws NacosException {
return getServicesOfServer(pageNo, pageSize, Constants.DEFAULT_GROUP, selector);
}
@Override
public ListView<String> getServicesOfServer(int pageNo, int pageSize, String groupName, AbstractSelector selector) throws NacosException {
return serverProxy.getServiceList(pageNo, pageSize, groupName, selector);
}
@Override
public List<ServiceInfo> getSubscribeServices() {
return eventDispatcher.getSubscribeServices();
}
@Override
public String getServerStatus() {
return serverProxy.serverHealthy() ? "UP" : "DOWN";
}
private List<Instance> selectInstances(ServiceInfo serviceInfo, boolean healthy) {
List<Instance> list;
if (serviceInfo == null || CollectionUtils.isEmpty(list = serviceInfo.getHosts())) {
return new ArrayList<Instance>();
}
Iterator<Instance> iterator = list.iterator();
while (iterator.hasNext()) {
Instance instance = iterator.next();
@ -468,14 +367,145 @@ public class NacosNamingService implements NamingService {
iterator.remove();
}
}
return list;
}
@Override
public Instance selectOneHealthyInstance(String serviceName) throws NacosException {
return selectOneHealthyInstance(serviceName, new ArrayList<String>());
}
@Override
public Instance selectOneHealthyInstance(String serviceName, String groupName) throws NacosException {
return selectOneHealthyInstance(serviceName, groupName, true);
}
@Override
public Instance selectOneHealthyInstance(String serviceName, boolean subscribe) throws NacosException {
return selectOneHealthyInstance(serviceName, new ArrayList<String>(), subscribe);
}
@Override
public Instance selectOneHealthyInstance(String serviceName, String groupName, boolean subscribe)
throws NacosException {
return selectOneHealthyInstance(serviceName, groupName, new ArrayList<String>(), subscribe);
}
@Override
public Instance selectOneHealthyInstance(String serviceName, List<String> clusters) throws NacosException {
return selectOneHealthyInstance(serviceName, clusters, true);
}
@Override
public Instance selectOneHealthyInstance(String serviceName, String groupName, List<String> clusters)
throws NacosException {
return selectOneHealthyInstance(serviceName, groupName, clusters, true);
}
@Override
public Instance selectOneHealthyInstance(String serviceName, List<String> clusters, boolean subscribe)
throws NacosException {
return selectOneHealthyInstance(serviceName, Constants.DEFAULT_GROUP, clusters, subscribe);
}
@Override
public Instance selectOneHealthyInstance(String serviceName, String groupName, List<String> clusters,
boolean subscribe) throws NacosException {
if (subscribe) {
return Balancer.RandomByWeight.selectHost(hostReactor
.getServiceInfo(NamingUtils.getGroupedName(serviceName, groupName),
StringUtils.join(clusters, ",")));
} else {
return Balancer.RandomByWeight.selectHost(hostReactor
.getServiceInfoDirectlyFromServer(NamingUtils.getGroupedName(serviceName, groupName),
StringUtils.join(clusters, ",")));
}
}
@Override
public void subscribe(String serviceName, EventListener listener) throws NacosException {
subscribe(serviceName, new ArrayList<String>(), listener);
}
@Override
public void subscribe(String serviceName, String groupName, EventListener listener) throws NacosException {
subscribe(serviceName, groupName, new ArrayList<String>(), listener);
}
@Override
public void subscribe(String serviceName, List<String> clusters, EventListener listener) throws NacosException {
subscribe(serviceName, Constants.DEFAULT_GROUP, clusters, listener);
}
@Override
public void subscribe(String serviceName, String groupName, List<String> clusters, EventListener listener)
throws NacosException {
eventDispatcher.addListener(hostReactor
.getServiceInfo(NamingUtils.getGroupedName(serviceName, groupName), StringUtils.join(clusters, ",")),
StringUtils.join(clusters, ","), listener);
}
@Override
public void unsubscribe(String serviceName, EventListener listener) throws NacosException {
unsubscribe(serviceName, new ArrayList<String>(), listener);
}
@Override
public void unsubscribe(String serviceName, String groupName, EventListener listener) throws NacosException {
unsubscribe(serviceName, groupName, new ArrayList<String>(), listener);
}
@Override
public void unsubscribe(String serviceName, List<String> clusters, EventListener listener) throws NacosException {
unsubscribe(serviceName, Constants.DEFAULT_GROUP, clusters, listener);
}
@Override
public void unsubscribe(String serviceName, String groupName, List<String> clusters, EventListener listener)
throws NacosException {
eventDispatcher
.removeListener(NamingUtils.getGroupedName(serviceName, groupName), StringUtils.join(clusters, ","),
listener);
}
@Override
public ListView<String> getServicesOfServer(int pageNo, int pageSize) throws NacosException {
return serverProxy.getServiceList(pageNo, pageSize, Constants.DEFAULT_GROUP);
}
@Override
public ListView<String> getServicesOfServer(int pageNo, int pageSize, String groupName) throws NacosException {
return getServicesOfServer(pageNo, pageSize, groupName, null);
}
@Override
public ListView<String> getServicesOfServer(int pageNo, int pageSize, AbstractSelector selector)
throws NacosException {
return getServicesOfServer(pageNo, pageSize, Constants.DEFAULT_GROUP, selector);
}
@Override
public ListView<String> getServicesOfServer(int pageNo, int pageSize, String groupName, AbstractSelector selector)
throws NacosException {
return serverProxy.getServiceList(pageNo, pageSize, groupName, selector);
}
@Override
public List<ServiceInfo> getSubscribeServices() {
return eventDispatcher.getSubscribeServices();
}
@Override
public String getServerStatus() {
return serverProxy.serverHealthy() ? "UP" : "DOWN";
}
public BeatReactor getBeatReactor() {
return beatReactor;
}
@Override
public void shutDown() throws NacosException {
beatReactor.shutdown();

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.backups;
import com.alibaba.nacos.api.exception.NacosException;
@ -24,7 +25,6 @@ import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import com.alibaba.nacos.client.naming.utils.UtilAndComs;
import com.alibaba.nacos.common.lifecycle.Closeable;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.common.utils.ThreadUtils;
@ -32,28 +32,32 @@ import java.io.BufferedReader;
import java.io.File;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.Date;
import java.util.Calendar;
import java.util.TimerTask;
import java.util.Date;
import java.util.HashMap;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;
import java.util.Map;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import static com.alibaba.nacos.client.utils.LogUtils.NAMING_LOGGER;
/**
* Failover reactor.
*
* @author nkorange
*/
public class FailoverReactor implements Closeable {
private String failoverDir;
private HostReactor hostReactor;
private ScheduledExecutorService executorService;
private final String failoverDir;
private final HostReactor hostReactor;
private final ScheduledExecutorService executorService;
public FailoverReactor(HostReactor hostReactor, String cacheDir) {
this.hostReactor = hostReactor;
this.failoverDir = cacheDir + "/failover";
@ -69,28 +73,33 @@ public class FailoverReactor implements Closeable {
});
this.init();
}
private Map<String, ServiceInfo> serviceMap = new ConcurrentHashMap<String, ServiceInfo>();
private Map<String, String> switchParams = new ConcurrentHashMap<String, String>();
private final Map<String, String> switchParams = new ConcurrentHashMap<String, String>();
private static final long DAY_PERIOD_MINUTES = 24 * 60;
/**
* Init.
*/
public void init() {
executorService.scheduleWithFixedDelay(new SwitchRefresher(), 0L, 5000L, TimeUnit.MILLISECONDS);
executorService.scheduleWithFixedDelay(new DiskFileWriter(), 30, DAY_PERIOD_MINUTES, TimeUnit.MINUTES);
// backup file on startup if failover directory is empty.
executorService.schedule(new Runnable() {
@Override
public void run() {
try {
File cacheDir = new File(failoverDir);
if (!cacheDir.exists() && !cacheDir.mkdirs()) {
throw new IllegalStateException("failed to create cache dir: " + failoverDir);
}
File[] files = cacheDir.listFiles();
if (files == null || files.length <= 0) {
new DiskFileWriter().run();
@ -98,18 +107,25 @@ public class FailoverReactor implements Closeable {
} catch (Throwable e) {
NAMING_LOGGER.error("[NA] failed to backup file on startup.", e);
}
}
}, 10000L, TimeUnit.MILLISECONDS);
}
/**
* Add day.
*
* @param date start time
* @param num add day number
* @return new date
*/
public Date addDay(Date date, int num) {
Calendar startDT = Calendar.getInstance();
startDT.setTime(date);
startDT.add(Calendar.DAY_OF_MONTH, num);
return startDT.getTime();
}
@Override
public void shutdown() throws NacosException {
String className = this.getClass().getName();
@ -117,10 +133,11 @@ public class FailoverReactor implements Closeable {
ThreadUtils.shutdownThreadPool(executorService, NAMING_LOGGER);
NAMING_LOGGER.info("{} do shutdown stop", className);
}
class SwitchRefresher implements Runnable {
long lastModifiedMillis = 0L;
@Override
public void run() {
try {
@ -130,16 +147,16 @@ public class FailoverReactor implements Closeable {
NAMING_LOGGER.debug("failover switch is not found, " + switchFile.getName());
return;
}
long modified = switchFile.lastModified();
if (lastModifiedMillis < modified) {
lastModifiedMillis = modified;
String failover = ConcurrentDiskUtil.getFileContent(failoverDir + UtilAndComs.FAILOVER_SWITCH,
Charset.defaultCharset().toString());
Charset.defaultCharset().toString());
if (!StringUtils.isEmpty(failover)) {
List<String> lines = Arrays.asList(failover.split(DiskCache.getLineSeparator()));
String[] lines = failover.split(DiskCache.getLineSeparator());
for (String line : lines) {
String line1 = line.trim();
if ("1".equals(line1)) {
@ -155,48 +172,48 @@ public class FailoverReactor implements Closeable {
switchParams.put("failover-mode", "false");
}
}
} catch (Throwable e) {
NAMING_LOGGER.error("[NA] failed to read failover switch.", e);
}
}
}
class FailoverFileReader implements Runnable {
@Override
public void run() {
Map<String, ServiceInfo> domMap = new HashMap<String, ServiceInfo>(16);
BufferedReader reader = null;
try {
File cacheDir = new File(failoverDir);
if (!cacheDir.exists() && !cacheDir.mkdirs()) {
throw new IllegalStateException("failed to create cache dir: " + failoverDir);
}
File[] files = cacheDir.listFiles();
if (files == null) {
return;
}
for (File file : files) {
if (!file.isFile()) {
continue;
}
if (file.getName().equals(UtilAndComs.FAILOVER_SWITCH)) {
continue;
}
ServiceInfo dom = new ServiceInfo(file.getName());
try {
String dataString = ConcurrentDiskUtil.getFileContent(file,
Charset.defaultCharset().toString());
String dataString = ConcurrentDiskUtil
.getFileContent(file, Charset.defaultCharset().toString());
reader = new BufferedReader(new StringReader(dataString));
String json;
if ((json = reader.readLine()) != null) {
try {
@ -205,7 +222,7 @@ public class FailoverReactor implements Closeable {
NAMING_LOGGER.error("[NA] error while parsing cached dom : " + json, e);
}
}
} catch (Exception e) {
NAMING_LOGGER.error("[NA] failed to read cache for dom: " + file.getName(), e);
} finally {
@ -224,44 +241,45 @@ public class FailoverReactor implements Closeable {
} catch (Exception e) {
NAMING_LOGGER.error("[NA] failed to read cache file", e);
}
if (domMap.size() > 0) {
serviceMap = domMap;
}
}
}
class DiskFileWriter extends TimerTask {
@Override
public void run() {
Map<String, ServiceInfo> map = hostReactor.getServiceInfoMap();
for (Map.Entry<String, ServiceInfo> entry : map.entrySet()) {
ServiceInfo serviceInfo = entry.getValue();
if (StringUtils.equals(serviceInfo.getKey(), UtilAndComs.ALL_IPS) || StringUtils.equals(
serviceInfo.getName(), UtilAndComs.ENV_LIST_KEY)
|| StringUtils.equals(serviceInfo.getName(), "00-00---000-ENV_CONFIGS-000---00-00")
|| StringUtils.equals(serviceInfo.getName(), "vipclient.properties")
|| StringUtils.equals(serviceInfo.getName(), "00-00---000-ALL_HOSTS-000---00-00")) {
if (StringUtils.equals(serviceInfo.getKey(), UtilAndComs.ALL_IPS) || StringUtils
.equals(serviceInfo.getName(), UtilAndComs.ENV_LIST_KEY) || StringUtils
.equals(serviceInfo.getName(), "00-00---000-ENV_CONFIGS-000---00-00") || StringUtils
.equals(serviceInfo.getName(), "vipclient.properties") || StringUtils
.equals(serviceInfo.getName(), "00-00---000-ALL_HOSTS-000---00-00")) {
continue;
}
DiskCache.write(serviceInfo, failoverDir);
}
}
}
public boolean isFailoverSwitch() {
return Boolean.parseBoolean(switchParams.get("failover-mode"));
}
public ServiceInfo getService(String key) {
ServiceInfo serviceInfo = serviceMap.get(key);
if (serviceInfo == null) {
serviceInfo = new ServiceInfo();
serviceInfo.setName(key);
}
return serviceInfo;
}
}

View File

@ -13,108 +13,111 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.beat;
import java.util.Map;
/**
* Beat information.
*
* @author nkorange
*/
public class BeatInfo {
private int port;
private String ip;
private double weight;
private String serviceName;
private String cluster;
private Map<String, String> metadata;
private volatile boolean scheduled;
private volatile long period;
private volatile boolean stopped;
@Override
public String toString() {
return "BeatInfo{" +
"port=" + port +
", ip='" + ip + '\'' +
", weight=" + weight +
", serviceName='" + serviceName + '\'' +
", cluster='" + cluster + '\'' +
", metadata=" + metadata +
", scheduled=" + scheduled +
", period=" + period +
", stopped=" + stopped +
'}';
return "BeatInfo{" + "port=" + port + ", ip='" + ip + '\'' + ", weight=" + weight + ", serviceName='"
+ serviceName + '\'' + ", cluster='" + cluster + '\'' + ", metadata=" + metadata + ", scheduled="
+ scheduled + ", period=" + period + ", stopped=" + stopped + '}';
}
public String getServiceName() {
return serviceName;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public String getCluster() {
return cluster;
}
public void setCluster(String cluster) {
this.cluster = cluster;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public Map<String, String> getMetadata() {
return metadata;
}
public void setMetadata(Map<String, String> metadata) {
this.metadata = metadata;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public boolean isScheduled() {
return scheduled;
}
public void setScheduled(boolean scheduled) {
this.scheduled = scheduled;
}
public long getPeriod() {
return period;
}
public void setPeriod(long period) {
this.period = period;
}
public boolean isStopped() {
return stopped;
}
public void setStopped(boolean stopped) {
this.stopped = stopped;
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.beat;
import com.alibaba.nacos.api.common.Constants;
@ -30,27 +31,33 @@ import com.alibaba.nacos.common.utils.ThreadUtils;
import com.fasterxml.jackson.databind.JsonNode;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import static com.alibaba.nacos.client.utils.LogUtils.NAMING_LOGGER;
/**
* Beat reactor.
*
* @author harold
*/
public class BeatReactor implements Closeable {
private ScheduledExecutorService executorService;
private NamingProxy serverProxy;
private final ScheduledExecutorService executorService;
private final NamingProxy serverProxy;
private boolean lightBeatEnabled = false;
public final Map<String, BeatInfo> dom2Beat = new ConcurrentHashMap<>();
public final Map<String, BeatInfo> dom2Beat = new ConcurrentHashMap<String, BeatInfo>();
public BeatReactor(NamingProxy serverProxy) {
this(serverProxy, UtilAndComs.DEFAULT_CLIENT_BEAT_THREAD_COUNT);
}
public BeatReactor(NamingProxy serverProxy, int threadCount) {
this.serverProxy = serverProxy;
this.executorService = new ScheduledThreadPoolExecutor(threadCount, new ThreadFactory() {
@ -63,7 +70,13 @@ public class BeatReactor implements Closeable {
}
});
}
/**
* Add beat information.
*
* @param serviceName service name
* @param beatInfo beat information
*/
public void addBeatInfo(String serviceName, BeatInfo beatInfo) {
NAMING_LOGGER.info("[BEAT] adding beat: {} to beat map.", beatInfo);
String key = buildKey(serviceName, beatInfo.getIp(), beatInfo.getPort());
@ -76,7 +89,14 @@ public class BeatReactor implements Closeable {
executorService.schedule(new BeatTask(beatInfo), beatInfo.getPeriod(), TimeUnit.MILLISECONDS);
MetricsMonitor.getDom2BeatSizeMonitor().set(dom2Beat.size());
}
/**
* Remove beat information.
*
* @param serviceName service name
* @param ip ip of beat information
* @param port port of beat information
*/
public void removeBeatInfo(String serviceName, String ip, int port) {
NAMING_LOGGER.info("[BEAT] removing beat: {}:{}:{} from beat map.", serviceName, ip, port);
BeatInfo beatInfo = dom2Beat.remove(buildKey(serviceName, ip, port));
@ -86,10 +106,27 @@ public class BeatReactor implements Closeable {
beatInfo.setStopped(true);
MetricsMonitor.getDom2BeatSizeMonitor().set(dom2Beat.size());
}
/**
* Build new beat information.
*
* @param instance instance
* @return new beat information
*/
public BeatInfo buildBeatInfo(Instance instance) {
return buildBeatInfo(instance.getServiceName(), instance);
}
/**
* Build new beat information.
*
* @param groupedServiceName service name with group name, format: ${groupName}@@${serviceName}
* @param instance instance
* @return new beat information
*/
public BeatInfo buildBeatInfo(String groupedServiceName, Instance instance) {
BeatInfo beatInfo = new BeatInfo();
beatInfo.setServiceName(instance.getServiceName());
beatInfo.setServiceName(groupedServiceName);
beatInfo.setIp(instance.getIp());
beatInfo.setPort(instance.getPort());
beatInfo.setCluster(instance.getClusterName());
@ -99,28 +136,27 @@ public class BeatReactor implements Closeable {
beatInfo.setPeriod(instance.getInstanceHeartBeatInterval());
return beatInfo;
}
public String buildKey(String serviceName, String ip, int port) {
return serviceName + Constants.NAMING_INSTANCE_ID_SPLITTER
+ ip + Constants.NAMING_INSTANCE_ID_SPLITTER + port;
return serviceName + Constants.NAMING_INSTANCE_ID_SPLITTER + ip + Constants.NAMING_INSTANCE_ID_SPLITTER + port;
}
@Override
public void shutdown() throws NacosException{
public void shutdown() throws NacosException {
String className = this.getClass().getName();
NAMING_LOGGER.info("{} do shutdown begin", className);
ThreadUtils.shutdownThreadPool(executorService, NAMING_LOGGER);
NAMING_LOGGER.info("{} do shutdown stop", className);
}
class BeatTask implements Runnable {
BeatInfo beatInfo;
public BeatTask(BeatInfo beatInfo) {
this.beatInfo = beatInfo;
}
@Override
public void run() {
if (beatInfo.isStopped()) {
@ -129,7 +165,7 @@ public class BeatReactor implements Closeable {
long nextTime = beatInfo.getPeriod();
try {
JsonNode result = serverProxy.sendBeat(beatInfo, BeatReactor.this.lightBeatEnabled);
long interval = result.get("clientBeatInterval").asInt();
long interval = result.get("clientBeatInterval").asLong();
boolean lightBeatEnabled = false;
if (result.has(CommonParams.LIGHT_BEAT_ENABLED)) {
lightBeatEnabled = result.get(CommonParams.LIGHT_BEAT_ENABLED).asBoolean();
@ -154,14 +190,14 @@ public class BeatReactor implements Closeable {
instance.setEphemeral(true);
try {
serverProxy.registerService(beatInfo.getServiceName(),
NamingUtils.getGroupName(beatInfo.getServiceName()), instance);
NamingUtils.getGroupName(beatInfo.getServiceName()), instance);
} catch (Exception ignore) {
}
}
} catch (NacosException ne) {
} catch (NacosException ex) {
NAMING_LOGGER.error("[CLIENT-BEAT] failed to send beat: {}, code: {}, msg: {}",
JacksonUtils.toJson(beatInfo), ne.getErrCode(), ne.getErrMsg());
JacksonUtils.toJson(beatInfo), ex.getErrCode(), ex.getErrMsg());
}
executorService.schedule(new BeatTask(beatInfo), nextTime, TimeUnit.MILLISECONDS);
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.cache;
import java.io.File;
@ -29,34 +30,34 @@ import java.nio.charset.CharsetDecoder;
import static com.alibaba.nacos.client.utils.LogUtils.NAMING_LOGGER;
/**
* Concurrent Disk util.
*
* @author nkorange
*/
public class ConcurrentDiskUtil {
/**
* get file content
* get file content.
*
* @param path file path
* @param charsetName charsetName
* @return content
* @throws IOException IOException
*/
public static String getFileContent(String path, String charsetName)
throws IOException {
public static String getFileContent(String path, String charsetName) throws IOException {
File file = new File(path);
return getFileContent(file, charsetName);
}
/**
* get file content
* get file content.
*
* @param file file
* @param charsetName charsetName
* @return content
* @throws IOException IOException
*/
public static String getFileContent(File file, String charsetName)
throws IOException {
public static String getFileContent(File file, String charsetName) throws IOException {
RandomAccessFile fis = null;
FileLock rlock = null;
try {
@ -70,14 +71,13 @@ public class ConcurrentDiskUtil {
++i;
if (i > RETRY_COUNT) {
NAMING_LOGGER.error("[NA] read " + file.getName() + " fail;retryed time: " + i, e);
throw new IOException("read " + file.getAbsolutePath()
+ " conflict");
throw new IOException("read " + file.getAbsolutePath() + " conflict");
}
sleep(SLEEP_BASETIME * i);
NAMING_LOGGER.warn("read " + file.getName() + " conflict;retry time: " + i);
}
} while (null == rlock);
int fileSize = (int)fcin.size();
int fileSize = (int) fcin.size();
ByteBuffer byteBuffer = ByteBuffer.allocate(fileSize);
fcin.read(byteBuffer);
byteBuffer.flip();
@ -93,9 +93,9 @@ public class ConcurrentDiskUtil {
}
}
}
/**
* write file content
* write file content.
*
* @param path file path
* @param content content
@ -103,14 +103,13 @@ public class ConcurrentDiskUtil {
* @return whether write ok
* @throws IOException IOException
*/
public static Boolean writeFileContent(String path, String content,
String charsetName) throws IOException {
public static Boolean writeFileContent(String path, String content, String charsetName) throws IOException {
File file = new File(path);
return writeFileContent(file, content, charsetName);
}
/**
* write file content
* write file content.
*
* @param file file
* @param content content
@ -118,9 +117,8 @@ public class ConcurrentDiskUtil {
* @return whether write ok
* @throws IOException IOException
*/
public static Boolean writeFileContent(File file, String content,
String charsetName) throws IOException {
public static Boolean writeFileContent(File file, String content, String charsetName) throws IOException {
if (!file.exists() && !file.createNewFile()) {
return false;
}
@ -138,16 +136,14 @@ public class ConcurrentDiskUtil {
++i;
if (i > RETRY_COUNT) {
NAMING_LOGGER.error("[NA] write {} fail;retryed time:{}", file.getName(), i);
throw new IOException("write " + file.getAbsolutePath()
+ " conflict", e);
throw new IOException("write " + file.getAbsolutePath() + " conflict", e);
}
sleep(SLEEP_BASETIME * i);
NAMING_LOGGER.warn("write " + file.getName() + " conflict;retry time: " + i);
}
} while (null == lock);
ByteBuffer sendBuffer = ByteBuffer.wrap(content
.getBytes(charsetName));
ByteBuffer sendBuffer = ByteBuffer.wrap(content.getBytes(charsetName));
while (sendBuffer.hasRemaining()) {
channel.write(sendBuffer);
}
@ -179,21 +175,20 @@ public class ConcurrentDiskUtil {
NAMING_LOGGER.warn("close wrong", e);
}
}
}
return true;
}
/**
* transfer ByteBuffer to String
* transfer ByteBuffer to String.
*
* @param buffer buffer
* @param charsetName charsetName
* @return String
* @throws IOException IOException
*/
public static String byteBufferToString(ByteBuffer buffer,
String charsetName) throws IOException {
public static String byteBufferToString(ByteBuffer buffer, String charsetName) throws IOException {
Charset charset = null;
CharsetDecoder decoder = null;
CharBuffer charBuffer = null;
@ -202,7 +197,7 @@ public class ConcurrentDiskUtil {
charBuffer = decoder.decode(buffer.asReadOnlyBuffer());
return charBuffer.toString();
}
private static void sleep(int time) {
try {
Thread.sleep(time);
@ -210,7 +205,8 @@ public class ConcurrentDiskUtil {
NAMING_LOGGER.warn("sleep wrong", e);
}
}
private static final int RETRY_COUNT = 10;
private static final int SLEEP_BASETIME = 10;
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.cache;
import com.alibaba.nacos.api.common.Constants;
@ -35,16 +36,23 @@ import java.util.Map;
import static com.alibaba.nacos.client.utils.LogUtils.NAMING_LOGGER;
/**
* Disk cache.
*
* @author xuanyin
*/
public class DiskCache {
/**
* Write service info to dir.
*
* @param dom service info
* @param dir directory
*/
public static void write(ServiceInfo dom, String dir) {
try {
makeSureCacheDirExists(dir);
File file = new File(dir, dom.getKeyEncoded());
if (!file.exists()) {
// add another !file.exists() to avoid conflicted creating-new-file from multi-instances
@ -52,68 +60,74 @@ public class DiskCache {
throw new IllegalStateException("failed to create cache file");
}
}
StringBuilder keyContentBuffer = new StringBuilder("");
StringBuilder keyContentBuffer = new StringBuilder();
String json = dom.getJsonFromServer();
if (StringUtils.isEmpty(json)) {
json = JacksonUtils.toJson(dom);
}
keyContentBuffer.append(json);
//Use the concurrent API to ensure the consistency.
ConcurrentDiskUtil.writeFileContent(file, keyContentBuffer.toString(), Charset.defaultCharset().toString());
} catch (Throwable e) {
NAMING_LOGGER.error("[NA] failed to write cache for dom:" + dom.getName(), e);
}
}
public static String getLineSeparator() {
return System.getProperty("line.separator");
}
/**
* Read service info from disk.
*
* @param cacheDir cache file dir
* @return service infos
*/
public static Map<String, ServiceInfo> read(String cacheDir) {
Map<String, ServiceInfo> domMap = new HashMap<String, ServiceInfo>(16);
BufferedReader reader = null;
try {
File[] files = makeSureCacheDirExists(cacheDir).listFiles();
if (files == null || files.length == 0) {
return domMap;
}
for (File file : files) {
if (!file.isFile()) {
continue;
}
String fileName = URLDecoder.decode(file.getName(), "UTF-8");
if (!(fileName.endsWith(Constants.SERVICE_INFO_SPLITER + "meta") || fileName.endsWith(
Constants.SERVICE_INFO_SPLITER + "special-url"))) {
if (!(fileName.endsWith(Constants.SERVICE_INFO_SPLITER + "meta") || fileName
.endsWith(Constants.SERVICE_INFO_SPLITER + "special-url"))) {
ServiceInfo dom = new ServiceInfo(fileName);
List<Instance> ips = new ArrayList<Instance>();
dom.setHosts(ips);
ServiceInfo newFormat = null;
try {
String dataString = ConcurrentDiskUtil.getFileContent(file,
Charset.defaultCharset().toString());
String dataString = ConcurrentDiskUtil
.getFileContent(file, Charset.defaultCharset().toString());
reader = new BufferedReader(new StringReader(dataString));
String json;
while ((json = reader.readLine()) != null) {
try {
if (!json.startsWith("{")) {
continue;
}
newFormat = JacksonUtils.toObj(json, ServiceInfo.class);
if (StringUtils.isEmpty(newFormat.getName())) {
ips.add(JacksonUtils.toObj(json, Instance.class));
}
@ -132,25 +146,25 @@ public class DiskCache {
//ignore
}
}
if (newFormat != null && !StringUtils.isEmpty(newFormat.getName()) && !CollectionUtils.isEmpty(
newFormat.getHosts())) {
if (newFormat != null && !StringUtils.isEmpty(newFormat.getName()) && !CollectionUtils
.isEmpty(newFormat.getHosts())) {
domMap.put(dom.getKey(), newFormat);
} else if (!CollectionUtils.isEmpty(dom.getHosts())) {
domMap.put(dom.getKey(), dom);
}
}
}
} catch (Throwable e) {
NAMING_LOGGER.error("[NA] failed to read cache file", e);
}
return domMap;
}
private static File makeSureCacheDirExists(String dir) {
File cacheDir = new File(dir);
if (!cacheDir.exists()) {
if (!cacheDir.mkdirs() && !cacheDir.exists()) {
throw new IllegalStateException("failed to create cache dir: " + dir);

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.core;
import com.alibaba.nacos.api.naming.pojo.Instance;
@ -27,34 +28,48 @@ import java.util.List;
import static com.alibaba.nacos.client.utils.LogUtils.NAMING_LOGGER;
/**
* Balancer.
*
* @author xuanyin
*/
public class Balancer {
public static class RandomByWeight {
/**
* Select all instance.
*
* @param serviceInfo service information
* @return all instance of services
*/
public static List<Instance> selectAll(ServiceInfo serviceInfo) {
List<Instance> hosts = serviceInfo.getHosts();
if (CollectionUtils.isEmpty(hosts)) {
throw new IllegalStateException("no host to srv for serviceInfo: " + serviceInfo.getName());
}
return hosts;
}
/**
* Random select one instance from service.
*
* @param dom service
* @return random instance
*/
public static Instance selectHost(ServiceInfo dom) {
List<Instance> hosts = selectAll(dom);
if (CollectionUtils.isEmpty(hosts)) {
throw new IllegalStateException("no host to srv for service: " + dom.getName());
}
return getHostByRandomWeight(hosts);
}
}
/**
* Return one host from the host list by random-weight.
*
@ -67,11 +82,7 @@ public class Balancer {
NAMING_LOGGER.debug("hosts == null || hosts.size() == 0");
return null;
}
Chooser<String, Instance> vipChooser = new Chooser<String, Instance>("www.taobao.com");
NAMING_LOGGER.debug("new Chooser");
List<Pair<Instance>> hostsWithWeight = new ArrayList<Pair<Instance>>();
for (Instance host : hosts) {
if (host.isHealthy()) {
@ -79,6 +90,7 @@ public class Balancer {
}
}
NAMING_LOGGER.debug("for (Host host : hosts)");
Chooser<String, Instance> vipChooser = new Chooser<String, Instance>("www.taobao.com");
vipChooser.refresh(hostsWithWeight);
NAMING_LOGGER.debug("vipChooser.refresh");
return vipChooser.randomWithWeight();

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.core;
import com.alibaba.nacos.api.exception.NacosException;
@ -28,55 +29,80 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import static com.alibaba.nacos.client.utils.LogUtils.NAMING_LOGGER;
/**
* Event dispatcher.
*
* @author xuanyin
*/
@SuppressWarnings("PMD.ThreadPoolCreationRule")
public class EventDispatcher implements Closeable {
private ExecutorService executor = null;
private BlockingQueue<ServiceInfo> changedServices = new LinkedBlockingQueue<ServiceInfo>();
private ConcurrentMap<String, List<EventListener>> observerMap
= new ConcurrentHashMap<String, List<EventListener>>();
private final BlockingQueue<ServiceInfo> changedServices = new LinkedBlockingQueue<ServiceInfo>();
private final ConcurrentMap<String, List<EventListener>> observerMap = new ConcurrentHashMap<String, List<EventListener>>();
private volatile boolean closed = false;
public EventDispatcher() {
this.executor = Executors.newSingleThreadExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r, "com.alibaba.nacos.naming.client.listener");
thread.setDaemon(true);
return thread;
}
});
this.executor.execute(new Notifier());
}
/**
* Add listener.
*
* @param serviceInfo service info
* @param clusters clusters
* @param listener listener
*/
public void addListener(ServiceInfo serviceInfo, String clusters, EventListener listener) {
NAMING_LOGGER.info("[LISTENER] adding " + serviceInfo.getName() + " with " + clusters + " to listener map");
List<EventListener> observers = Collections.synchronizedList(new ArrayList<EventListener>());
observers.add(listener);
observers = observerMap.putIfAbsent(ServiceInfo.getKey(serviceInfo.getName(), clusters), observers);
if (observers != null) {
observers.add(listener);
}
serviceChanged(serviceInfo);
}
/**
* Remove listener.
*
* @param serviceName service name
* @param clusters clusters
* @param listener listener
*/
public void removeListener(String serviceName, String clusters, EventListener listener) {
NAMING_LOGGER.info("[LISTENER] removing " + serviceName + " with " + clusters + " from listener map");
List<EventListener> observers = observerMap.get(ServiceInfo.getKey(serviceName, clusters));
if (observers != null) {
Iterator<EventListener> iter = observers.iterator();
@ -91,11 +117,11 @@ public class EventDispatcher implements Closeable {
}
}
}
public boolean isSubscribed(String serviceName, String clusters) {
return observerMap.containsKey(ServiceInfo.getKey(serviceName, clusters));
}
public List<ServiceInfo> getSubscribeServices() {
List<ServiceInfo> serviceInfos = new ArrayList<ServiceInfo>();
for (String key : observerMap.keySet()) {
@ -103,50 +129,59 @@ public class EventDispatcher implements Closeable {
}
return serviceInfos;
}
/**
* Service changed.
*
* @param serviceInfo service info
*/
public void serviceChanged(ServiceInfo serviceInfo) {
if (serviceInfo == null) {
return;
}
changedServices.add(serviceInfo);
}
@Override
public void shutdown() throws NacosException {
String className = this.getClass().getName();
NAMING_LOGGER.info("{} do shutdown begin", className);
ThreadUtils.shutdownThreadPool(executor, NAMING_LOGGER);
closed = true;
NAMING_LOGGER.info("{} do shutdown stop", className);
}
private class Notifier implements Runnable {
@Override
public void run() {
while (true) {
while (!closed) {
ServiceInfo serviceInfo = null;
try {
serviceInfo = changedServices.poll(5, TimeUnit.MINUTES);
} catch (Exception ignore) {
}
if (serviceInfo == null) {
continue;
}
try {
List<EventListener> listeners = observerMap.get(serviceInfo.getKey());
if (!CollectionUtils.isEmpty(listeners)) {
for (EventListener listener : listeners) {
List<Instance> hosts = Collections.unmodifiableList(serviceInfo.getHosts());
listener.onEvent(new NamingEvent(serviceInfo.getName(), serviceInfo.getGroupName(), serviceInfo.getClusters(), hosts));
listener.onEvent(new NamingEvent(serviceInfo.getName(), serviceInfo.getGroupName(),
serviceInfo.getClusters(), hosts));
}
}
} catch (Exception e) {
NAMING_LOGGER.error("[NA] notify error for service: "
+ serviceInfo.getName() + ", clusters: " + serviceInfo.getClusters(), e);
NAMING_LOGGER.error("[NA] notify error for service: " + serviceInfo.getName() + ", clusters: "
+ serviceInfo.getClusters(), e);
}
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.core;
import com.alibaba.nacos.api.exception.NacosException;
@ -30,57 +31,59 @@ import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.common.utils.ThreadUtils;
import java.util.HashSet;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import static com.alibaba.nacos.client.utils.LogUtils.NAMING_LOGGER;
/**
* Host reactor.
*
* @author xuanyin
*/
public class HostReactor implements Closeable {
private static final long DEFAULT_DELAY = 1000L;
private static final long UPDATE_HOLD_INTERVAL = 5000L;
private final Map<String, ScheduledFuture<?>> futureMap = new HashMap<String, ScheduledFuture<?>>();
private Map<String, ServiceInfo> serviceInfoMap;
private Map<String, Object> updatingMap;
private PushReceiver pushReceiver;
private EventDispatcher eventDispatcher;
private BeatReactor beatReactor;
private NamingProxy serverProxy;
private FailoverReactor failoverReactor;
private String cacheDir;
private ScheduledExecutorService executor;
public HostReactor(EventDispatcher eventDispatcher, NamingProxy serverProxy, BeatReactor beatReactor, String cacheDir) {
private final Map<String, ServiceInfo> serviceInfoMap;
private final Map<String, Object> updatingMap;
private final PushReceiver pushReceiver;
private final EventDispatcher eventDispatcher;
private final BeatReactor beatReactor;
private final NamingProxy serverProxy;
private final FailoverReactor failoverReactor;
private final String cacheDir;
private final ScheduledExecutorService executor;
public HostReactor(EventDispatcher eventDispatcher, NamingProxy serverProxy, BeatReactor beatReactor,
String cacheDir) {
this(eventDispatcher, serverProxy, beatReactor, cacheDir, false, UtilAndComs.DEFAULT_POLLING_THREAD_COUNT);
}
public HostReactor(EventDispatcher eventDispatcher, NamingProxy serverProxy, BeatReactor beatReactor, String cacheDir,
boolean loadCacheAtStart, int pollingThreadCount) {
public HostReactor(EventDispatcher eventDispatcher, NamingProxy serverProxy, BeatReactor beatReactor,
String cacheDir, boolean loadCacheAtStart, int pollingThreadCount) {
// init executorService
this.executor = new ScheduledThreadPoolExecutor(pollingThreadCount, new ThreadFactory() {
@Override
@ -100,128 +103,134 @@ public class HostReactor implements Closeable {
} else {
this.serviceInfoMap = new ConcurrentHashMap<String, ServiceInfo>(16);
}
this.updatingMap = new ConcurrentHashMap<String, Object>();
this.failoverReactor = new FailoverReactor(this, cacheDir);
this.pushReceiver = new PushReceiver(this);
}
public Map<String, ServiceInfo> getServiceInfoMap() {
return serviceInfoMap;
}
public synchronized ScheduledFuture<?> addTask(UpdateTask task) {
return executor.schedule(task, DEFAULT_DELAY, TimeUnit.MILLISECONDS);
}
public ServiceInfo processServiceJSON(String json) {
/**
* Process service json.
*
* @param json service json
* @return service info
*/
public ServiceInfo processServiceJson(String json) {
ServiceInfo serviceInfo = JacksonUtils.toObj(json, ServiceInfo.class);
ServiceInfo oldService = serviceInfoMap.get(serviceInfo.getKey());
if (serviceInfo.getHosts() == null || !serviceInfo.validate()) {
//empty or error push, just ignore
return oldService;
}
boolean changed = false;
if (oldService != null) {
if (oldService.getLastRefTime() > serviceInfo.getLastRefTime()) {
NAMING_LOGGER.warn("out of date data received, old-t: " + oldService.getLastRefTime()
+ ", new-t: " + serviceInfo.getLastRefTime());
NAMING_LOGGER.warn("out of date data received, old-t: " + oldService.getLastRefTime() + ", new-t: "
+ serviceInfo.getLastRefTime());
}
serviceInfoMap.put(serviceInfo.getKey(), serviceInfo);
Map<String, Instance> oldHostMap = new HashMap<String, Instance>(oldService.getHosts().size());
for (Instance host : oldService.getHosts()) {
oldHostMap.put(host.toInetAddr(), host);
}
Map<String, Instance> newHostMap = new HashMap<String, Instance>(serviceInfo.getHosts().size());
for (Instance host : serviceInfo.getHosts()) {
newHostMap.put(host.toInetAddr(), host);
}
Set<Instance> modHosts = new HashSet<Instance>();
Set<Instance> newHosts = new HashSet<Instance>();
Set<Instance> remvHosts = new HashSet<Instance>();
List<Map.Entry<String, Instance>> newServiceHosts = new ArrayList<Map.Entry<String, Instance>>(
newHostMap.entrySet());
newHostMap.entrySet());
for (Map.Entry<String, Instance> entry : newServiceHosts) {
Instance host = entry.getValue();
String key = entry.getKey();
if (oldHostMap.containsKey(key) && !StringUtils.equals(host.toString(),
oldHostMap.get(key).toString())) {
if (oldHostMap.containsKey(key) && !StringUtils
.equals(host.toString(), oldHostMap.get(key).toString())) {
modHosts.add(host);
continue;
}
if (!oldHostMap.containsKey(key)) {
newHosts.add(host);
}
}
for (Map.Entry<String, Instance> entry : oldHostMap.entrySet()) {
Instance host = entry.getValue();
String key = entry.getKey();
if (newHostMap.containsKey(key)) {
continue;
}
if (!newHostMap.containsKey(key)) {
remvHosts.add(host);
}
}
if (newHosts.size() > 0) {
changed = true;
NAMING_LOGGER.info("new ips(" + newHosts.size() + ") service: "
+ serviceInfo.getKey() + " -> " + JacksonUtils.toJson(newHosts));
NAMING_LOGGER.info("new ips(" + newHosts.size() + ") service: " + serviceInfo.getKey() + " -> "
+ JacksonUtils.toJson(newHosts));
}
if (remvHosts.size() > 0) {
changed = true;
NAMING_LOGGER.info("removed ips(" + remvHosts.size() + ") service: "
+ serviceInfo.getKey() + " -> " + JacksonUtils.toJson(remvHosts));
NAMING_LOGGER.info("removed ips(" + remvHosts.size() + ") service: " + serviceInfo.getKey() + " -> "
+ JacksonUtils.toJson(remvHosts));
}
if (modHosts.size() > 0) {
changed = true;
updateBeatInfo(modHosts);
NAMING_LOGGER.info("modified ips(" + modHosts.size() + ") service: "
+ serviceInfo.getKey() + " -> " + JacksonUtils.toJson(modHosts));
NAMING_LOGGER.info("modified ips(" + modHosts.size() + ") service: " + serviceInfo.getKey() + " -> "
+ JacksonUtils.toJson(modHosts));
}
serviceInfo.setJsonFromServer(json);
if (newHosts.size() > 0 || remvHosts.size() > 0 || modHosts.size() > 0) {
eventDispatcher.serviceChanged(serviceInfo);
DiskCache.write(serviceInfo, cacheDir);
}
} else {
changed = true;
NAMING_LOGGER.info("init new ips(" + serviceInfo.ipCount() + ") service: " + serviceInfo.getKey() + " -> " +
JacksonUtils.toJson(serviceInfo.getHosts()));
NAMING_LOGGER.info("init new ips(" + serviceInfo.ipCount() + ") service: " + serviceInfo.getKey() + " -> "
+ JacksonUtils.toJson(serviceInfo.getHosts()));
serviceInfoMap.put(serviceInfo.getKey(), serviceInfo);
eventDispatcher.serviceChanged(serviceInfo);
serviceInfo.setJsonFromServer(json);
DiskCache.write(serviceInfo, cacheDir);
}
MetricsMonitor.getServiceInfoMapSizeMonitor().set(serviceInfoMap.size());
if (changed) {
NAMING_LOGGER.info("current ips:(" + serviceInfo.ipCount() + ") service: " + serviceInfo.getKey() +
" -> " + JacksonUtils.toJson(serviceInfo.getHosts()));
NAMING_LOGGER.info("current ips:(" + serviceInfo.ipCount() + ") service: " + serviceInfo.getKey() + " -> "
+ JacksonUtils.toJson(serviceInfo.getHosts()));
}
return serviceInfo;
}
private void updateBeatInfo(Set<Instance> modHosts) {
for (Instance instance : modHosts) {
String key = beatReactor.buildKey(instance.getServiceName(), instance.getIp(), instance.getPort());
@ -231,84 +240,97 @@ public class HostReactor implements Closeable {
}
}
}
private ServiceInfo getServiceInfo0(String serviceName, String clusters) {
String key = ServiceInfo.getKey(serviceName, clusters);
return serviceInfoMap.get(key);
}
public ServiceInfo getServiceInfoDirectlyFromServer(final String serviceName, final String clusters) throws NacosException {
public ServiceInfo getServiceInfoDirectlyFromServer(final String serviceName, final String clusters)
throws NacosException {
String result = serverProxy.queryList(serviceName, clusters, 0, false);
if (StringUtils.isNotEmpty(result)) {
return JacksonUtils.toObj(result, ServiceInfo.class);
}
return null;
}
public ServiceInfo getServiceInfo(final String serviceName, final String clusters) {
NAMING_LOGGER.debug("failover-mode: " + failoverReactor.isFailoverSwitch());
String key = ServiceInfo.getKey(serviceName, clusters);
if (failoverReactor.isFailoverSwitch()) {
return failoverReactor.getService(key);
}
ServiceInfo serviceObj = getServiceInfo0(serviceName, clusters);
if (null == serviceObj) {
serviceObj = new ServiceInfo(serviceName, clusters);
serviceInfoMap.put(serviceObj.getKey(), serviceObj);
updatingMap.put(serviceName, new Object());
updateServiceNow(serviceName, clusters);
updatingMap.remove(serviceName);
} else if (updatingMap.containsKey(serviceName)) {
if (UPDATE_HOLD_INTERVAL > 0) {
// hold a moment waiting for update finish
synchronized (serviceObj) {
try {
serviceObj.wait(UPDATE_HOLD_INTERVAL);
} catch (InterruptedException e) {
NAMING_LOGGER.error("[getServiceInfo] serviceName:" + serviceName + ", clusters:" + clusters, e);
NAMING_LOGGER
.error("[getServiceInfo] serviceName:" + serviceName + ", clusters:" + clusters, e);
}
}
}
}
scheduleUpdateIfAbsent(serviceName, clusters);
return serviceInfoMap.get(serviceObj.getKey());
}
/**
* Schedule update if absent.
*
* @param serviceName service name
* @param clusters clusters
*/
public void scheduleUpdateIfAbsent(String serviceName, String clusters) {
if (futureMap.get(ServiceInfo.getKey(serviceName, clusters)) != null) {
return;
}
synchronized (futureMap) {
if (futureMap.get(ServiceInfo.getKey(serviceName, clusters)) != null) {
return;
}
ScheduledFuture<?> future = addTask(new UpdateTask(serviceName, clusters));
futureMap.put(ServiceInfo.getKey(serviceName, clusters), future);
}
}
/**
* Update service now.
*
* @param serviceName service name
* @param clusters clusters
*/
public void updateServiceNow(String serviceName, String clusters) {
ServiceInfo oldService = getServiceInfo0(serviceName, clusters);
try {
String result = serverProxy.queryList(serviceName, clusters, pushReceiver.getUDPPort(), false);
String result = serverProxy.queryList(serviceName, clusters, pushReceiver.getUdpPort(), false);
if (StringUtils.isNotEmpty(result)) {
processServiceJSON(result);
processServiceJson(result);
}
} catch (Exception e) {
NAMING_LOGGER.error("[NA] failed to update serviceName: " + serviceName, e);
@ -320,46 +342,57 @@ public class HostReactor implements Closeable {
}
}
}
/**
* Refresh only.
*
* @param serviceName service name
* @param clusters cluster
*/
public void refreshOnly(String serviceName, String clusters) {
try {
serverProxy.queryList(serviceName, clusters, pushReceiver.getUDPPort(), false);
serverProxy.queryList(serviceName, clusters, pushReceiver.getUdpPort(), false);
} catch (Exception e) {
NAMING_LOGGER.error("[NA] failed to update serviceName: " + serviceName, e);
}
}
@Override
public void shutdown() throws NacosException {
String className = this.getClass().getName();
NAMING_LOGGER.info("{} do shutdown begin", className);
ThreadUtils.shutdownThreadPool(executor, NAMING_LOGGER);
pushReceiver.shutdown();
failoverReactor.shutdown();
NAMING_LOGGER.info("{} do shutdown stop", className);
}
public class UpdateTask implements Runnable {
long lastRefTime = Long.MAX_VALUE;
private String clusters;
private String serviceName;
private final String clusters;
private final String serviceName;
public UpdateTask(String serviceName, String clusters) {
this.serviceName = serviceName;
this.clusters = clusters;
}
@Override
public void run() {
long delayTime = -1;
try {
ServiceInfo serviceObj = serviceInfoMap.get(ServiceInfo.getKey(serviceName, clusters));
if (serviceObj == null) {
updateServiceNow(serviceName, clusters);
delayTime = DEFAULT_DELAY;
return;
}
if (serviceObj.getLastRefTime() <= lastRefTime) {
updateServiceNow(serviceName, clusters);
serviceObj = serviceInfoMap.get(ServiceInfo.getKey(serviceName, clusters));
@ -368,19 +401,18 @@ public class HostReactor implements Closeable {
// since the push data may be different from pull through force push
refreshOnly(serviceName, clusters);
}
lastRefTime = serviceObj.getLastRefTime();
if (!eventDispatcher.isSubscribed(serviceName, clusters) &&
!futureMap.containsKey(ServiceInfo.getKey(serviceName, clusters))) {
// abort the update task:
if (!eventDispatcher.isSubscribed(serviceName, clusters) && !futureMap
.containsKey(ServiceInfo.getKey(serviceName, clusters))) {
// abort the update task
NAMING_LOGGER.info("update task is stopped, service:" + serviceName + ", clusters:" + clusters);
return;
}
delayTime = serviceObj.getCacheMillis();
} catch (Throwable e) {
NAMING_LOGGER.warn("[NA] failed to update serviceName: " + serviceName, e);
} finally {
@ -388,7 +420,7 @@ public class HostReactor implements Closeable {
executor.schedule(this, delayTime, TimeUnit.MILLISECONDS);
}
}
}
}
}

View File

@ -13,23 +13,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.core;
/**
* Protect mode.
*
* @author nkorange
*/
public class ProtectMode {
private float protectThreshold;
public ProtectMode() {
this.protectThreshold = 0.8F;
}
public float getProtectThreshold() {
return protectThreshold;
}
public void setProtectThreshold(float protectThreshold) {
this.protectThreshold = protectThreshold;
}

View File

@ -13,18 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.core;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.common.lifecycle.Closeable;
import com.alibaba.nacos.common.utils.IoUtils;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.common.utils.IoUtils;
import com.alibaba.nacos.common.utils.ThreadUtils;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
@ -32,23 +33,26 @@ import java.util.concurrent.ThreadFactory;
import static com.alibaba.nacos.client.utils.LogUtils.NAMING_LOGGER;
/**
* Push receiver.
*
* @author xuanyin
*/
public class PushReceiver implements Runnable, Closeable {
private ScheduledExecutorService executorService;
private static final int UDP_MSS = 64 * 1024;
private DatagramSocket udpSocket;
private HostReactor hostReactor;
private volatile boolean closed = false;
public PushReceiver(HostReactor hostReactor) {
try {
this.hostReactor = hostReactor;
this.udpSocket = new DatagramSocket();
this.executorService = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
@ -58,72 +62,74 @@ public class PushReceiver implements Runnable, Closeable {
return thread;
}
});
this.executorService.execute(this);
} catch (Exception e) {
NAMING_LOGGER.error("[NA] init udp socket failed", e);
}
}
@Override
public void run() {
while (true) {
while (!closed) {
try {
// byte[] is initialized with 0 full filled by default
byte[] buffer = new byte[UDP_MSS];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
udpSocket.receive(packet);
String json = new String(IoUtils.tryDecompress(packet.getData()), "UTF-8").trim();
String json = new String(IoUtils.tryDecompress(packet.getData()), StandardCharsets.UTF_8).trim();
NAMING_LOGGER.info("received push data: " + json + " from " + packet.getAddress().toString());
PushPacket pushPacket = JacksonUtils.toObj(json, PushPacket.class);
String ack;
if ("dom".equals(pushPacket.type) || "service".equals(pushPacket.type)) {
hostReactor.processServiceJSON(pushPacket.data);
hostReactor.processServiceJson(pushPacket.data);
// send ack to server
ack = "{\"type\": \"push-ack\""
+ ", \"lastRefTime\":\"" + pushPacket.lastRefTime
+ "\", \"data\":" + "\"\"}";
ack = "{\"type\": \"push-ack\"" + ", \"lastRefTime\":\"" + pushPacket.lastRefTime + "\", \"data\":"
+ "\"\"}";
} else if ("dump".equals(pushPacket.type)) {
// dump data to server
ack = "{\"type\": \"dump-ack\""
+ ", \"lastRefTime\": \"" + pushPacket.lastRefTime
+ "\", \"data\":" + "\""
+ StringUtils.escapeJavaScript(JacksonUtils.toJson(hostReactor.getServiceInfoMap()))
+ "\"}";
ack = "{\"type\": \"dump-ack\"" + ", \"lastRefTime\": \"" + pushPacket.lastRefTime + "\", \"data\":"
+ "\"" + StringUtils.escapeJavaScript(JacksonUtils.toJson(hostReactor.getServiceInfoMap()))
+ "\"}";
} else {
// do nothing send ack only
ack = "{\"type\": \"unknown-ack\""
+ ", \"lastRefTime\":\"" + pushPacket.lastRefTime
+ "\", \"data\":" + "\"\"}";
ack = "{\"type\": \"unknown-ack\"" + ", \"lastRefTime\":\"" + pushPacket.lastRefTime
+ "\", \"data\":" + "\"\"}";
}
udpSocket.send(new DatagramPacket(ack.getBytes(Charset.forName("UTF-8")),
ack.getBytes(Charset.forName("UTF-8")).length, packet.getSocketAddress()));
udpSocket.send(new DatagramPacket(ack.getBytes(StandardCharsets.UTF_8),
ack.getBytes(StandardCharsets.UTF_8).length, packet.getSocketAddress()));
} catch (Exception e) {
NAMING_LOGGER.error("[NA] error while receiving push data", e);
}
}
}
@Override
public void shutdown() throws NacosException {
String className = this.getClass().getName();
NAMING_LOGGER.info("{} do shutdown begin", className);
ThreadUtils.shutdownThreadPool(executorService, NAMING_LOGGER);
closed = true;
udpSocket.close();
NAMING_LOGGER.info("{} do shutdown stop", className);
}
public static class PushPacket {
public String type;
public long lastRefTime;
public String data;
}
public int getUDPPort() {
public int getUdpPort() {
return this.udpSocket.getLocalPort();
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.net;
import com.alibaba.nacos.api.common.Constants;
@ -29,51 +30,70 @@ import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URL;
import java.net.URLEncoder;
import java.util.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import static com.alibaba.nacos.client.utils.LogUtils.NAMING_LOGGER;
/**
* Http client.
*
* @author nkorange
* @deprecated Use NacosRestTemplate{@link NacosRestTemplate} unified http client
*/
@Deprecated
public class HttpClient {
public static final int READ_TIME_OUT_MILLIS = Integer
.getInteger("com.alibaba.nacos.client.naming.rtimeout", 50000);
public static final int CON_TIME_OUT_MILLIS = Integer
.getInteger("com.alibaba.nacos.client.naming.ctimeout", 3000);
private static final boolean ENABLE_HTTPS = Boolean
.getBoolean("com.alibaba.nacos.client.naming.tls.enable");
.getInteger("com.alibaba.nacos.client.naming.rtimeout", 50000);
public static final int CON_TIME_OUT_MILLIS = Integer.getInteger("com.alibaba.nacos.client.naming.ctimeout", 3000);
private static final boolean ENABLE_HTTPS = Boolean.getBoolean("com.alibaba.nacos.client.naming.tls.enable");
static {
// limit max redirection
System.setProperty("http.maxRedirects", "5");
}
public static String getPrefix() {
if (ENABLE_HTTPS) {
return "https://";
}
return "http://";
}
public static HttpResult httpGet(String url, List<String> headers, Map<String, String> paramValues, String encoding) {
public static HttpResult httpGet(String url, List<String> headers, Map<String, String> paramValues,
String encoding) {
return request(url, headers, paramValues, StringUtils.EMPTY, encoding, HttpMethod.GET);
}
public static HttpResult request(String url, List<String> headers, Map<String, String> paramValues, String body, String encoding, String method) {
/**
* request.
*
* @param url url
* @param headers headers
* @param paramValues paramValues
* @param body body
* @param encoding encoding
* @param method method
* @return result
*/
public static HttpResult request(String url, List<String> headers, Map<String, String> paramValues, String body,
String encoding, String method) {
HttpURLConnection conn = null;
try {
String encodedContent = encodingParams(paramValues, encoding);
url += (StringUtils.isEmpty(encodedContent)) ? "" : ("?" + encodedContent);
conn = (HttpURLConnection) new URL(url).openConnection();
setHeaders(conn, headers, encoding);
conn.setConnectTimeout(CON_TIME_OUT_MILLIS);
conn.setReadTimeout(READ_TIME_OUT_MILLIS);
@ -94,46 +114,45 @@ public class HttpClient {
} catch (Exception e) {
try {
if (conn != null) {
NAMING_LOGGER.warn("failed to request " + conn.getURL() + " from "
+ InetAddress.getByName(conn.getURL().getHost()).getHostAddress());
NAMING_LOGGER.warn("failed to request " + conn.getURL() + " from " + InetAddress
.getByName(conn.getURL().getHost()).getHostAddress());
}
} catch (Exception e1) {
NAMING_LOGGER.error("[NA] failed to request ", e1);
} catch (Exception ex) {
NAMING_LOGGER.error("[NA] failed to request ", ex);
//ignore
}
NAMING_LOGGER.error("[NA] failed to request ", e);
return new HttpResult(500, e.toString(), Collections.<String, String>emptyMap());
} finally {
IoUtils.closeQuietly(conn);
}
}
private static HttpResult getResult(HttpURLConnection conn) throws IOException {
int respCode = conn.getResponseCode();
InputStream inputStream;
if (HttpURLConnection.HTTP_OK == respCode
|| HttpURLConnection.HTTP_NOT_MODIFIED == respCode
|| Constants.WRITE_REDIRECT_CODE == respCode) {
if (HttpURLConnection.HTTP_OK == respCode || HttpURLConnection.HTTP_NOT_MODIFIED == respCode
|| Constants.WRITE_REDIRECT_CODE == respCode) {
inputStream = conn.getInputStream();
} else {
inputStream = conn.getErrorStream();
}
Map<String, String> respHeaders = new HashMap<String, String>(conn.getHeaderFields().size());
for (Map.Entry<String, List<String>> entry : conn.getHeaderFields().entrySet()) {
respHeaders.put(entry.getKey(), entry.getValue().get(0));
}
String encodingGzip = "gzip";
if (encodingGzip.equals(respHeaders.get(HttpHeaders.CONTENT_ENCODING))) {
inputStream = new GZIPInputStream(inputStream);
}
HttpResult httpResult = new HttpResult(respCode, IoUtils.toString(inputStream, getCharset(conn)), respHeaders);
//InputStream from HttpURLConnection can be closed automatically,but new GZIPInputStream can't be closed automatically
//so needs to close it manually
if (inputStream instanceof GZIPInputStream) {
@ -141,86 +160,88 @@ public class HttpClient {
}
return httpResult;
}
private static String getCharset(HttpURLConnection conn) {
String contentType = conn.getContentType();
if (StringUtils.isEmpty(contentType)) {
return "UTF-8";
}
String[] values = contentType.split(";");
if (values.length == 0) {
return "UTF-8";
}
String charset = "UTF-8";
for (String value : values) {
value = value.trim();
if (value.toLowerCase().startsWith("charset=")) {
charset = value.substring("charset=".length());
}
}
return charset;
}
private static void setHeaders(HttpURLConnection conn, List<String> headers, String encoding) {
if (null != headers) {
for (Iterator<String> iter = headers.iterator(); iter.hasNext(); ) {
conn.addRequestProperty(iter.next(), iter.next());
}
}
conn.addRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset="
+ encoding);
conn.addRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + encoding);
conn.addRequestProperty("Accept-Charset", encoding);
}
private static String encodingParams(Map<String, String> params, String encoding)
throws UnsupportedEncodingException {
throws UnsupportedEncodingException {
if (null == params || params.isEmpty()) {
return "";
}
params.put("encoding", encoding);
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {
if (StringUtils.isEmpty(entry.getValue())) {
continue;
}
sb.append(entry.getKey()).append("=");
sb.append(URLEncoder.encode(entry.getValue(), encoding));
sb.append("&");
}
if (sb.length() > 0) {
sb = sb.deleteCharAt(sb.length() - 1);
}
return sb.toString();
}
public static class HttpResult {
final public int code;
final public String content;
final private Map<String, String> respHeaders;
public final int code;
public final String content;
private final Map<String, String> respHeaders;
public HttpResult(int code, String content, Map<String, String> respHeaders) {
this.code = code;
this.content = content;
this.respHeaders = respHeaders;
}
public String getHeader(String name) {
return respHeaders.get(name);
}
@Override
public String toString() {
return "HttpResult{" + "code=" + code + ", content='" + content + '\''
+ ", respHeaders=" + respHeaders + '}';
return "HttpResult{" + "code=" + code + ", content='" + content + '\'' + ", respHeaders=" + respHeaders
+ '}';
}
}
}

View File

@ -16,48 +16,79 @@
package com.alibaba.nacos.client.naming.net;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.common.http.AbstractHttpClientFactory;
import com.alibaba.nacos.common.http.HttpClientBeanHolder;
import com.alibaba.nacos.common.http.HttpClientConfig;
import com.alibaba.nacos.common.http.HttpClientFactory;
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
import com.alibaba.nacos.common.lifecycle.Closeable;
import com.alibaba.nacos.common.utils.ExceptionUtil;
import org.slf4j.Logger;
import static com.alibaba.nacos.client.utils.LogUtils.NAMING_LOGGER;
/**
* http Manager
* http Manager.
*
* @author mai.jh
*/
public class NamingHttpClientManager {
public class NamingHttpClientManager implements Closeable {
private static final int READ_TIME_OUT_MILLIS = Integer
.getInteger("com.alibaba.nacos.client.naming.rtimeout", 50000);
private static final int CON_TIME_OUT_MILLIS = Integer
.getInteger("com.alibaba.nacos.client.naming.ctimeout", 3000);
private static final boolean ENABLE_HTTPS = Boolean
.getBoolean("com.alibaba.nacos.client.naming.tls.enable");
.getInteger("com.alibaba.nacos.client.naming.rtimeout", 50000);
private static final int CON_TIME_OUT_MILLIS = Integer.getInteger("com.alibaba.nacos.client.naming.ctimeout", 3000);
private static final boolean ENABLE_HTTPS = Boolean.getBoolean("com.alibaba.nacos.client.naming.tls.enable");
private static final int MAX_REDIRECTS = 5;
private static final HttpClientFactory HTTP_CLIENT_FACTORY = new NamingHttpClientFactory();
public static String getPrefix() {
private static class NamingHttpClientManagerInstance {
private static final NamingHttpClientManager INSTANCE = new NamingHttpClientManager();
}
public static NamingHttpClientManager getInstance() {
return NamingHttpClientManagerInstance.INSTANCE;
}
public String getPrefix() {
if (ENABLE_HTTPS) {
return "https://";
}
return "http://";
}
public static NacosRestTemplate getNacosRestTemplate() {
public NacosRestTemplate getNacosRestTemplate() {
return HttpClientBeanHolder.getNacosRestTemplate(HTTP_CLIENT_FACTORY);
}
@Override
public void shutdown() throws NacosException {
NAMING_LOGGER.warn("[NamingHttpClientManager] Start destroying NacosRestTemplate");
try {
HttpClientBeanHolder.shutdownNacostSyncRest(HTTP_CLIENT_FACTORY.getClass().getName());
} catch (Exception ex) {
NAMING_LOGGER.error("[NamingHttpClientManager] An exception occurred when the HTTP client was closed : {}",
ExceptionUtil.getStackTrace(ex));
}
NAMING_LOGGER.warn("[NamingHttpClientManager] Destruction of the end");
}
private static class NamingHttpClientFactory extends AbstractHttpClientFactory {
@Override
protected HttpClientConfig buildHttpClientConfig() {
return HttpClientConfig.builder()
.setConTimeOutMillis(CON_TIME_OUT_MILLIS)
.setReadTimeOutMillis(READ_TIME_OUT_MILLIS)
.setMaxRedirects(MAX_REDIRECTS).build();
return HttpClientConfig.builder().setConTimeOutMillis(CON_TIME_OUT_MILLIS)
.setReadTimeOutMillis(READ_TIME_OUT_MILLIS).setMaxRedirects(MAX_REDIRECTS).build();
}
@Override
protected Logger assignLogger() {
return NAMING_LOGGER;
}
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.net;
import com.alibaba.nacos.api.PropertyKeyConst;
@ -42,66 +43,72 @@ import com.alibaba.nacos.common.http.client.NacosRestTemplate;
import com.alibaba.nacos.common.http.param.Header;
import com.alibaba.nacos.common.http.param.Query;
import com.alibaba.nacos.common.lifecycle.Closeable;
import com.alibaba.nacos.common.utils.*;
import com.alibaba.nacos.common.utils.HttpMethod;
import com.alibaba.nacos.common.utils.IoUtils;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.common.utils.ThreadUtils;
import com.alibaba.nacos.common.utils.UuidUtils;
import com.alibaba.nacos.common.utils.VersionUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.http.HttpStatus;
import java.io.IOException;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.Map;
import java.util.HashMap;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.Callable;
import static com.alibaba.nacos.client.utils.LogUtils.NAMING_LOGGER;
/**
* Naming proxy.
*
* @author nkorange
*/
public class NamingProxy implements Closeable {
private NacosRestTemplate nacosRestTemplate = NamingHttpClientManager.getNacosRestTemplate();
private final NacosRestTemplate nacosRestTemplate = NamingHttpClientManager.getInstance().getNacosRestTemplate();
private static final int DEFAULT_SERVER_PORT = 8848;
private int serverPort = DEFAULT_SERVER_PORT;
private String namespaceId;
private String endpoint;
private final String namespaceId;
private final String endpoint;
private String nacosDomain;
private List<String> serverList;
private List<String> serversFromEndpoint = new ArrayList<String>();
private SecurityProxy securityProxy;
private final SecurityProxy securityProxy;
private long lastSrvRefTime = 0L;
private long vipSrvRefInterMillis = TimeUnit.SECONDS.toMillis(30);
private long securityInfoRefreshIntervalMills = TimeUnit.SECONDS.toMillis(5);
private final long vipSrvRefInterMillis = TimeUnit.SECONDS.toMillis(30);
private final long securityInfoRefreshIntervalMills = TimeUnit.SECONDS.toMillis(5);
private Properties properties;
private ScheduledExecutorService executorService;
public NamingProxy(String namespaceId, String endpoint, String serverList, Properties properties) {
this.securityProxy = new SecurityProxy(properties);
this.properties = properties;
this.setServerPort(DEFAULT_SERVER_PORT);
@ -115,9 +122,9 @@ public class NamingProxy implements Closeable {
}
this.initRefreshTask();
}
private void initRefreshTask() {
this.executorService = new ScheduledThreadPoolExecutor(2, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
@ -127,37 +134,36 @@ public class NamingProxy implements Closeable {
return t;
}
});
this.executorService.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
refreshSrvIfNeed();
}
}, 0, vipSrvRefInterMillis, TimeUnit.MILLISECONDS);
this.executorService.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
securityProxy.login(getServerList());
}
}, 0, securityInfoRefreshIntervalMills, TimeUnit.MILLISECONDS);
refreshSrvIfNeed();
this.securityProxy.login(getServerList());
}
public List<String> getServerListFromEndpoint() {
try {
String urlString = "http://" + endpoint + "/nacos/serverlist";
Header header = builderHeader();
HttpRestResult<String> restResult = nacosRestTemplate.get(urlString, header, Query.EMPTY, String.class);
if (!restResult.ok()) {
throw new IOException("Error while requesting: " + urlString + "'. Server returned: "
+ restResult.getCode());
throw new IOException(
"Error while requesting: " + urlString + "'. Server returned: " + restResult.getCode());
}
String content = restResult.getData();
List<String> list = new ArrayList<String>();
for (String line : IoUtils.readLines(new StringReader(content))) {
@ -165,50 +171,58 @@ public class NamingProxy implements Closeable {
list.add(line.trim());
}
}
return list;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private void refreshSrvIfNeed() {
try {
if (!CollectionUtils.isEmpty(serverList)) {
NAMING_LOGGER.debug("server list provided by user: " + serverList);
return;
}
if (System.currentTimeMillis() - lastSrvRefTime < vipSrvRefInterMillis) {
return;
}
List<String> list = getServerListFromEndpoint();
if (CollectionUtils.isEmpty(list)) {
throw new Exception("Can not acquire Nacos list");
}
if (!CollectionUtils.isEqualCollection(list, serversFromEndpoint)) {
NAMING_LOGGER.info("[SERVER-LIST] server list is updated: " + list);
}
serversFromEndpoint = list;
lastSrvRefTime = System.currentTimeMillis();
} catch (Throwable e) {
NAMING_LOGGER.warn("failed to update server list", e);
}
}
/**
* register a instance to service with specified instance properties.
*
* @param serviceName name of service
* @param groupName group of service
* @param instance instance to register
* @throws NacosException nacos exception
*/
public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {
NAMING_LOGGER.info("[REGISTER-SERVICE] {} registering service {} with instance: {}",
namespaceId, serviceName, instance);
NAMING_LOGGER.info("[REGISTER-SERVICE] {} registering service {} with instance: {}", namespaceId, serviceName,
instance);
final Map<String, String> params = new HashMap<String, String>(16);
params.put(CommonParams.NAMESPACE_ID, namespaceId);
params.put(CommonParams.SERVICE_NAME, serviceName);
@ -221,16 +235,24 @@ public class NamingProxy implements Closeable {
params.put("healthy", String.valueOf(instance.isHealthy()));
params.put("ephemeral", String.valueOf(instance.isEphemeral()));
params.put("metadata", JacksonUtils.toJson(instance.getMetadata()));
reqAPI(UtilAndComs.NACOS_URL_INSTANCE, params, HttpMethod.POST);
reqApi(UtilAndComs.nacosUrlInstance, params, HttpMethod.POST);
}
/**
* deregister instance from a service.
*
* @param serviceName name of service
* @param instance instance
* @throws NacosException nacos exception
*/
public void deregisterService(String serviceName, Instance instance) throws NacosException {
NAMING_LOGGER.info("[DEREGISTER-SERVICE] {} deregistering service {} with instance: {}",
namespaceId, serviceName, instance);
NAMING_LOGGER
.info("[DEREGISTER-SERVICE] {} deregistering service {} with instance: {}", namespaceId, serviceName,
instance);
final Map<String, String> params = new HashMap<String, String>(8);
params.put(CommonParams.NAMESPACE_ID, namespaceId);
params.put(CommonParams.SERVICE_NAME, serviceName);
@ -238,14 +260,22 @@ public class NamingProxy implements Closeable {
params.put("ip", instance.getIp());
params.put("port", String.valueOf(instance.getPort()));
params.put("ephemeral", String.valueOf(instance.isEphemeral()));
reqAPI(UtilAndComs.NACOS_URL_INSTANCE, params, HttpMethod.DELETE);
reqApi(UtilAndComs.nacosUrlInstance, params, HttpMethod.DELETE);
}
/**
* Update instance to service.
*
* @param serviceName service name
* @param groupName group name
* @param instance instance
* @throws NacosException nacos exception
*/
public void updateInstance(String serviceName, String groupName, Instance instance) throws NacosException {
NAMING_LOGGER.info("[UPDATE-SERVICE] {} update service {} with instance: {}",
namespaceId, serviceName, instance);
NAMING_LOGGER
.info("[UPDATE-SERVICE] {} update service {} with instance: {}", namespaceId, serviceName, instance);
final Map<String, String> params = new HashMap<String, String>(8);
params.put(CommonParams.NAMESPACE_ID, namespaceId);
params.put(CommonParams.SERVICE_NAME, serviceName);
@ -257,28 +287,41 @@ public class NamingProxy implements Closeable {
params.put("enabled", String.valueOf(instance.isEnabled()));
params.put("ephemeral", String.valueOf(instance.isEphemeral()));
params.put("metadata", JacksonUtils.toJson(instance.getMetadata()));
reqAPI(UtilAndComs.NACOS_URL_INSTANCE, params, HttpMethod.PUT);
reqApi(UtilAndComs.nacosUrlInstance, params, HttpMethod.PUT);
}
/**
* Query Service.
*
* @param serviceName service name
* @param groupName group name
* @return service
* @throws NacosException nacos exception
*/
public Service queryService(String serviceName, String groupName) throws NacosException {
NAMING_LOGGER.info("[QUERY-SERVICE] {} query service : {}, {}",
namespaceId, serviceName, groupName);
NAMING_LOGGER.info("[QUERY-SERVICE] {} query service : {}, {}", namespaceId, serviceName, groupName);
final Map<String, String> params = new HashMap<String, String>(3);
params.put(CommonParams.NAMESPACE_ID, namespaceId);
params.put(CommonParams.SERVICE_NAME, serviceName);
params.put(CommonParams.GROUP_NAME, groupName);
String result = reqAPI(UtilAndComs.NACOS_URL_SERVICE, params, HttpMethod.GET);
String result = reqApi(UtilAndComs.nacosUrlService, params, HttpMethod.GET);
return JacksonUtils.toObj(result, Service.class);
}
/**
* Create service.
*
* @param service service
* @param selector selector
* @throws NacosException nacos exception
*/
public void createService(Service service, AbstractSelector selector) throws NacosException {
NAMING_LOGGER.info("[CREATE-SERVICE] {} creating service : {}",
namespaceId, service);
NAMING_LOGGER.info("[CREATE-SERVICE] {} creating service : {}", namespaceId, service);
final Map<String, String> params = new HashMap<String, String>(6);
params.put(CommonParams.NAMESPACE_ID, namespaceId);
params.put(CommonParams.SERVICE_NAME, service.getName());
@ -286,28 +329,42 @@ public class NamingProxy implements Closeable {
params.put("protectThreshold", String.valueOf(service.getProtectThreshold()));
params.put("metadata", JacksonUtils.toJson(service.getMetadata()));
params.put("selector", JacksonUtils.toJson(selector));
reqAPI(UtilAndComs.NACOS_URL_SERVICE, params, HttpMethod.POST);
reqApi(UtilAndComs.nacosUrlService, params, HttpMethod.POST);
}
/**
* Delete service.
*
* @param serviceName service name
* @param groupName group name
* @return true if delete ok
* @throws NacosException nacos exception
*/
public boolean deleteService(String serviceName, String groupName) throws NacosException {
NAMING_LOGGER.info("[DELETE-SERVICE] {} deleting service : {} with groupName : {}",
namespaceId, serviceName, groupName);
NAMING_LOGGER.info("[DELETE-SERVICE] {} deleting service : {} with groupName : {}", namespaceId, serviceName,
groupName);
final Map<String, String> params = new HashMap<String, String>(6);
params.put(CommonParams.NAMESPACE_ID, namespaceId);
params.put(CommonParams.SERVICE_NAME, serviceName);
params.put(CommonParams.GROUP_NAME, groupName);
String result = reqAPI(UtilAndComs.NACOS_URL_SERVICE, params, HttpMethod.DELETE);
String result = reqApi(UtilAndComs.nacosUrlService, params, HttpMethod.DELETE);
return "ok".equals(result);
}
/**
* Update service.
*
* @param service service
* @param selector selector
* @throws NacosException nacos exception
*/
public void updateService(Service service, AbstractSelector selector) throws NacosException {
NAMING_LOGGER.info("[UPDATE-SERVICE] {} updating service : {}",
namespaceId, service);
NAMING_LOGGER.info("[UPDATE-SERVICE] {} updating service : {}", namespaceId, service);
final Map<String, String> params = new HashMap<String, String>(6);
params.put(CommonParams.NAMESPACE_ID, namespaceId);
params.put(CommonParams.SERVICE_NAME, service.getName());
@ -315,13 +372,23 @@ public class NamingProxy implements Closeable {
params.put("protectThreshold", String.valueOf(service.getProtectThreshold()));
params.put("metadata", JacksonUtils.toJson(service.getMetadata()));
params.put("selector", JacksonUtils.toJson(selector));
reqAPI(UtilAndComs.NACOS_URL_SERVICE, params, HttpMethod.PUT);
reqApi(UtilAndComs.nacosUrlService, params, HttpMethod.PUT);
}
/**
* Query instance list.
*
* @param serviceName service name
* @param clusters clusters
* @param udpPort udp port
* @param healthyOnly healthy only
* @return instance list
* @throws NacosException nacos exception
*/
public String queryList(String serviceName, String clusters, int udpPort, boolean healthyOnly)
throws NacosException {
throws NacosException {
final Map<String, String> params = new HashMap<String, String>(8);
params.put(CommonParams.NAMESPACE_ID, namespaceId);
params.put(CommonParams.SERVICE_NAME, serviceName);
@ -329,38 +396,47 @@ public class NamingProxy implements Closeable {
params.put("udpPort", String.valueOf(udpPort));
params.put("clientIP", NetUtils.localIP());
params.put("healthyOnly", String.valueOf(healthyOnly));
return reqAPI(UtilAndComs.NACOS_URL_BASE + "/instance/list", params, HttpMethod.GET);
return reqApi(UtilAndComs.nacosUrlBase + "/instance/list", params, HttpMethod.GET);
}
/**
* Send beat.
*
* @param beatInfo beat info
* @param lightBeatEnabled light beat
* @return beat result
* @throws NacosException nacos exception
*/
public JsonNode sendBeat(BeatInfo beatInfo, boolean lightBeatEnabled) throws NacosException {
if (NAMING_LOGGER.isDebugEnabled()) {
NAMING_LOGGER.debug("[BEAT] {} sending beat to server: {}", namespaceId, beatInfo.toString());
}
Map<String, String> params = new HashMap<String, String>(8);
Map<String, String> bodyMap = new HashMap<String, String>(2);
if (!lightBeatEnabled) {
try {
bodyMap.put("beat", URLEncoder.encode(JacksonUtils.toJson(beatInfo), "UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new NacosException(NacosException.SERVER_ERROR, "encode beatInfo error", e);
}
bodyMap.put("beat", JacksonUtils.toJson(beatInfo));
}
params.put(CommonParams.NAMESPACE_ID, namespaceId);
params.put(CommonParams.SERVICE_NAME, beatInfo.getServiceName());
params.put(CommonParams.CLUSTER_NAME, beatInfo.getCluster());
params.put("ip", beatInfo.getIp());
params.put("port", String.valueOf(beatInfo.getPort()));
String result = reqAPI(UtilAndComs.NACOS_URL_BASE + "/instance/beat", params, bodyMap, HttpMethod.PUT);
String result = reqApi(UtilAndComs.nacosUrlBase + "/instance/beat", params, bodyMap, HttpMethod.PUT);
return JacksonUtils.toObj(result);
}
/**
* Check Server healthy.
*
* @return true if server is healthy
*/
public boolean serverHealthy() {
try {
String result = reqAPI(UtilAndComs.NACOS_URL_BASE + "/operator/metrics",
new HashMap<String, String>(2), HttpMethod.GET);
String result = reqApi(UtilAndComs.nacosUrlBase + "/operator/metrics", new HashMap<String, String>(2),
HttpMethod.GET);
JsonNode json = JacksonUtils.toObj(result);
String serverStatus = json.get("status").asText();
return "UP".equals(serverStatus);
@ -368,19 +444,20 @@ public class NamingProxy implements Closeable {
return false;
}
}
public ListView<String> getServiceList(int pageNo, int pageSize, String groupName) throws NacosException {
return getServiceList(pageNo, pageSize, groupName, null);
}
public ListView<String> getServiceList(int pageNo, int pageSize, String groupName, AbstractSelector selector) throws NacosException {
public ListView<String> getServiceList(int pageNo, int pageSize, String groupName, AbstractSelector selector)
throws NacosException {
Map<String, String> params = new HashMap<String, String>(4);
params.put("pageNo", String.valueOf(pageNo));
params.put("pageSize", String.valueOf(pageSize));
params.put(CommonParams.NAMESPACE_ID, namespaceId);
params.put(CommonParams.GROUP_NAME, groupName);
if (selector != null) {
switch (SelectorType.valueOf(selector.getType())) {
case none:
@ -393,89 +470,54 @@ public class NamingProxy implements Closeable {
break;
}
}
String result = reqAPI(UtilAndComs.NACOS_URL_BASE + "/service/list", params, HttpMethod.GET);
String result = reqApi(UtilAndComs.nacosUrlBase + "/service/list", params, HttpMethod.GET);
JsonNode json = JacksonUtils.toObj(result);
ListView<String> listView = new ListView<>();
ListView<String> listView = new ListView<String>();
listView.setCount(json.get("count").asInt());
listView.setData(JacksonUtils.toObj(json.get("doms").toString(), new TypeReference<List<String>>() {}));
listView.setData(JacksonUtils.toObj(json.get("doms").toString(), new TypeReference<List<String>>() {
}));
return listView;
}
public String reqAPI(String api, Map<String, String> params, String method) throws NacosException {
return reqAPI(api, params, Collections.EMPTY_MAP, method);
public String reqApi(String api, Map<String, String> params, String method) throws NacosException {
return reqApi(api, params, Collections.EMPTY_MAP, method);
}
public String reqAPI(String api, Map<String, String> params, Map<String, String> body, String method) throws NacosException {
return reqAPI(api, params, body, getServerList(), method);
public String reqApi(String api, Map<String, String> params, Map<String, String> body, String method)
throws NacosException {
return reqApi(api, params, body, getServerList(), method);
}
private List<String> getServerList() {
List<String> snapshot = serversFromEndpoint;
if (!CollectionUtils.isEmpty(serverList)) {
snapshot = serverList;
}
return snapshot;
}
public String callServer(String api, Map<String, String> params, Map<String, String> body, String curServer) throws NacosException {
return callServer(api, params, body, curServer, HttpMethod.GET);
}
public String callServer(String api, Map<String, String> params, Map<String, String> body, String curServer, String method)
throws NacosException {
long start = System.currentTimeMillis();
long end = 0;
injectSecurityInfo(params);
Header header = builderHeader();
String url;
if (curServer.startsWith(UtilAndComs.HTTPS) || curServer.startsWith(UtilAndComs.HTTP)) {
url = curServer + api;
} else {
if (!curServer.contains(UtilAndComs.SERVER_ADDR_IP_SPLITER)) {
curServer = curServer + UtilAndComs.SERVER_ADDR_IP_SPLITER + serverPort;
}
url = NamingHttpClientManager.getPrefix() + curServer + api;
}
try {
HttpRestResult<String> restResult = nacosRestTemplate.exchangeForm(url, header, params, body, method, String.class);
end = System.currentTimeMillis();
MetricsMonitor.getNamingRequestMonitor(method, url, String.valueOf(restResult.getCode()))
.observe(end - start);
if (restResult.ok()) {
return restResult.getData();
}
if (HttpStatus.SC_NOT_MODIFIED == restResult.getCode()) {
return StringUtils.EMPTY;
}
throw new NacosException(restResult.getCode(), restResult.getData());
} catch (Exception e) {
NAMING_LOGGER.error("[NA] failed to request", e);
throw new NacosException(NacosException.SERVER_ERROR, e);
}
}
public String reqAPI(String api, Map<String, String> params, Map<String, String> body, List<String> servers, String method) throws NacosException {
/**
* Request api.
*
* @param api api
* @param params parameters
* @param body body
* @param servers servers
* @param method http method
* @return result
* @throws NacosException nacos exception
*/
public String reqApi(String api, Map<String, String> params, Map<String, String> body, List<String> servers,
String method) throws NacosException {
params.put(CommonParams.NAMESPACE_ID, getNamespaceId());
if (CollectionUtils.isEmpty(servers) && StringUtils.isEmpty(nacosDomain)) {
throw new NacosException(NacosException.INVALID_PARAM, "no server available");
}
NacosException exception = new NacosException();
if (servers != null && !servers.isEmpty()) {
Random random = new Random(System.currentTimeMillis());
int index = random.nextInt(servers.size());
for (int i = 0; i < servers.size(); i++) {
String server = servers.get(index);
try {
@ -489,7 +531,7 @@ public class NamingProxy implements Closeable {
index = (index + 1) % servers.size();
}
}
if (StringUtils.isNotBlank(nacosDomain)) {
for (int i = 0; i < UtilAndComs.REQUEST_DOMAIN_RETRY_COUNT; i++) {
try {
@ -502,22 +544,84 @@ public class NamingProxy implements Closeable {
}
}
}
NAMING_LOGGER.error("request: {} failed, servers: {}, code: {}, msg: {}",
api, servers, exception.getErrCode(), exception.getErrMsg());
throw new NacosException(exception.getErrCode(), "failed to req API:" + api + " after all servers(" + servers + ") tried: "
+ exception.getMessage());
NAMING_LOGGER.error("request: {} failed, servers: {}, code: {}, msg: {}", api, servers, exception.getErrCode(),
exception.getErrMsg());
throw new NacosException(exception.getErrCode(),
"failed to req API:" + api + " after all servers(" + servers + ") tried: " + exception.getMessage());
}
private List<String> getServerList() {
List<String> snapshot = serversFromEndpoint;
if (!CollectionUtils.isEmpty(serverList)) {
snapshot = serverList;
}
return snapshot;
}
public String callServer(String api, Map<String, String> params, Map<String, String> body, String curServer)
throws NacosException {
return callServer(api, params, body, curServer, HttpMethod.GET);
}
/**
* Call server.
*
* @param api api
* @param params parameters
* @param body body
* @param curServer ?
* @param method http method
* @return result
* @throws NacosException nacos exception
*/
public String callServer(String api, Map<String, String> params, Map<String, String> body, String curServer,
String method) throws NacosException {
long start = System.currentTimeMillis();
long end = 0;
injectSecurityInfo(params);
Header header = builderHeader();
String url;
if (curServer.startsWith(UtilAndComs.HTTPS) || curServer.startsWith(UtilAndComs.HTTP)) {
url = curServer + api;
} else {
if (!curServer.contains(UtilAndComs.SERVER_ADDR_IP_SPLITER)) {
curServer = curServer + UtilAndComs.SERVER_ADDR_IP_SPLITER + serverPort;
}
url = NamingHttpClientManager.getInstance().getPrefix() + curServer + api;
}
try {
HttpRestResult<String> restResult = nacosRestTemplate
.exchangeForm(url, header, params, body, method, String.class);
end = System.currentTimeMillis();
MetricsMonitor.getNamingRequestMonitor(method, url, String.valueOf(restResult.getCode()))
.observe(end - start);
if (restResult.ok()) {
return restResult.getData();
}
if (HttpStatus.SC_NOT_MODIFIED == restResult.getCode()) {
return StringUtils.EMPTY;
}
throw new NacosException(restResult.getCode(), restResult.getData());
} catch (Exception e) {
NAMING_LOGGER.error("[NA] failed to request", e);
throw new NacosException(NacosException.SERVER_ERROR, e);
}
}
private void injectSecurityInfo(Map<String, String> params) {
// Inject token if exist:
if (StringUtils.isNotBlank(securityProxy.getAccessToken())) {
params.put(Constants.ACCESS_TOKEN, securityProxy.getAccessToken());
}
// Inject ak/sk if exist:
String ak = getAccessKey();
String sk = getSecretKey();
@ -534,7 +638,12 @@ public class NamingProxy implements Closeable {
}
}
}
/**
* Build header.
*
* @return header
*/
public Header builderHeader() {
Header header = Header.newInstance();
header.addParam(HttpHeaderConsts.CLIENT_VERSION_HEADER, VersionUtils.version);
@ -545,65 +654,67 @@ public class NamingProxy implements Closeable {
header.addParam(HttpHeaderConsts.REQUEST_MODULE, "Naming");
return header;
}
private static String getSignData(String serviceName) {
return StringUtils.isNotEmpty(serviceName)
? System.currentTimeMillis() + "@@" + serviceName
: String.valueOf(System.currentTimeMillis());
return StringUtils.isNotEmpty(serviceName) ? System.currentTimeMillis() + "@@" + serviceName
: String.valueOf(System.currentTimeMillis());
}
public String getAccessKey() {
if (properties == null) {
return SpasAdapter.getAk();
}
return TemplateUtils.stringEmptyAndThenExecute(properties.getProperty(PropertyKeyConst.ACCESS_KEY), new Callable<String>() {
@Override
public String call() {
return SpasAdapter.getAk();
}
});
return TemplateUtils
.stringEmptyAndThenExecute(properties.getProperty(PropertyKeyConst.ACCESS_KEY), new Callable<String>() {
@Override
public String call() {
return SpasAdapter.getAk();
}
});
}
public String getSecretKey() {
if (properties == null) {
return SpasAdapter.getSk();
}
return TemplateUtils.stringEmptyAndThenExecute(properties.getProperty(PropertyKeyConst.SECRET_KEY), new Callable<String>() {
@Override
public String call() throws Exception {
return SpasAdapter.getSk();
}
});
return TemplateUtils
.stringEmptyAndThenExecute(properties.getProperty(PropertyKeyConst.SECRET_KEY), new Callable<String>() {
@Override
public String call() throws Exception {
return SpasAdapter.getSk();
}
});
}
public void setProperties(Properties properties) {
this.properties = properties;
setServerPort(DEFAULT_SERVER_PORT);
}
public String getNamespaceId() {
return namespaceId;
}
public void setServerPort(int serverPort) {
this.serverPort = serverPort;
String sp = System.getProperty(SystemPropertyKeyConst.NAMING_SERVER_PORT);
if (StringUtils.isNotBlank(sp)) {
this.serverPort = Integer.parseInt(sp);
}
}
@Override
public void shutdown() throws NacosException{
public void shutdown() throws NacosException {
String className = this.getClass().getName();
NAMING_LOGGER.info("{} do shutdown begin", className);
ThreadUtils.shutdownThreadPool(executorService, NAMING_LOGGER);
NamingHttpClientManager.getInstance().shutdown();
NAMING_LOGGER.info("{} do shutdown stop", className);
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.utils;
import java.util.ArrayList;
@ -20,14 +21,21 @@ import java.util.Arrays;
import java.util.List;
/**
* Chooser.
*
* @author alibaba
*/
public class Chooser<K, T> {
private K uniqueKey;
private final K uniqueKey;
private volatile Ref<T> ref;
/**
* Random get one item.
*
* @return item
*/
public T random() {
List<T> items = ref.items;
if (items.size() == 0) {
@ -38,7 +46,12 @@ public class Chooser<K, T> {
}
return items.get(ThreadLocalRandom.current().nextInt(items.size()));
}
/**
* Random get one item with weight.
*
* @return item
*/
public T randomWithWeight() {
Ref<T> ref = this.ref;
double random = ThreadLocalRandom.current().nextDouble(0, 1);
@ -48,67 +61,78 @@ public class Chooser<K, T> {
} else {
return ref.items.get(index);
}
if (index >= 0 && index < ref.weights.length) {
if (random < ref.weights[index]) {
return ref.items.get(index);
}
}
/* This should never happen, but it ensures we will return a correct
* object in case there is some floating point inequality problem
* wrt the cumulative probabilities. */
return ref.items.get(ref.items.size() - 1);
}
public Chooser(K uniqueKey) {
this(uniqueKey, new ArrayList<Pair<T>>());
}
public Chooser(K uniqueKey, List<Pair<T>> pairs) {
Ref<T> ref = new Ref<T>(pairs);
ref.refresh();
this.uniqueKey = uniqueKey;
this.ref = ref;
}
public K getUniqueKey() {
return uniqueKey;
}
public Ref<T> getRef() {
return ref;
}
/**
* refresh items.
*
* @param itemsWithWeight items with weight
*/
public void refresh(List<Pair<T>> itemsWithWeight) {
Ref<T> newRef = new Ref<T>(itemsWithWeight);
newRef.refresh();
newRef.poller = this.ref.poller.refresh(newRef.items);
this.ref = newRef;
}
public class Ref<T> {
private List<Pair<T>> itemsWithWeight = new ArrayList<Pair<T>>();
private List<T> items = new ArrayList<T>();
private final List<T> items = new ArrayList<T>();
private Poller<T> poller = new GenericPoller<T>(items);
private double[] weights;
@SuppressWarnings("unchecked")
public Ref(List<Pair<T>> itemsWithWeight) {
this.itemsWithWeight = itemsWithWeight;
}
/**
* Refresh.
*/
public void refresh() {
Double originWeightSum = (double) 0;
for (Pair<T> item : itemsWithWeight) {
double weight = item.weight();
//ignore item which weight is zero.see test_randomWithWeight_weight0 in ChooserTest
if (weight <= 0) {
continue;
}
items.add(item.item());
if (Double.isInfinite(weight)) {
weight = 10000.0D;
@ -118,7 +142,7 @@ public class Chooser<K, T> {
}
originWeightSum += weight;
}
double[] exactWeights = new double[items.size()];
int index = 0;
for (Pair<T> item : itemsWithWeight) {
@ -129,27 +153,28 @@ public class Chooser<K, T> {
}
exactWeights[index++] = singleWeight / originWeightSum;
}
weights = new double[items.size()];
double randomRange = 0D;
for (int i = 0; i < index; i++) {
weights[i] = randomRange + exactWeights[i];
randomRange += exactWeights[i];
}
double doublePrecisionDelta = 0.0001;
if (index == 0 || (Math.abs(weights[index - 1] - 1) < doublePrecisionDelta)) {
return;
}
throw new IllegalStateException("Cumulative Weight caculate wrong , the sum of probabilities does not equals 1.");
throw new IllegalStateException(
"Cumulative Weight caculate wrong , the sum of probabilities does not equals 1.");
}
@Override
public int hashCode() {
return itemsWithWeight.hashCode();
}
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object other) {
@ -167,9 +192,7 @@ public class Chooser<K, T> {
}
Ref<T> otherRef = (Ref<T>) other;
if (itemsWithWeight == null) {
if (otherRef.itemsWithWeight != null) {
return false;
}
return otherRef.itemsWithWeight == null;
} else {
if (otherRef.itemsWithWeight == null) {
return false;
@ -177,15 +200,14 @@ public class Chooser<K, T> {
return this.itemsWithWeight.equals(otherRef.itemsWithWeight);
}
}
return true;
}
}
@Override
public int hashCode() {
return uniqueKey.hashCode();
}
@Override
public boolean equals(Object other) {
if (this == other) {
@ -197,7 +219,7 @@ public class Chooser<K, T> {
if (getClass() != other.getClass()) {
return false;
}
Chooser otherChooser = (Chooser) other;
if (this.uniqueKey == null) {
if (otherChooser.getUniqueKey() != null) {
@ -209,22 +231,17 @@ public class Chooser<K, T> {
} else if (!this.uniqueKey.equals(otherChooser.getUniqueKey())) {
return false;
}
}
if (this.ref == null) {
if (otherChooser.getRef() != null) {
return false;
}
return otherChooser.getRef() == null;
} else {
if (otherChooser.getRef() == null) {
return false;
} else if (!this.ref.equals(otherChooser.getRef())) {
return false;
} else {
return this.ref.equals(otherChooser.getRef());
}
}
return true;
}
}

View File

@ -13,13 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.utils;
/**
* Created by harold on 2015/12/7.
*/
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* Provides utility methods and decorators for {@link Collection} instances.
@ -41,22 +42,22 @@ import java.util.*;
* @since Commons Collections 1.0
*/
public class CollectionUtils {
/**
* Constant to avoid repeated object creation
* Constant to avoid repeated object creation.
*/
private static final Integer INTEGER_ONE = 1;
/**
* <code>CollectionUtils</code> should not normally be instantiated.
*/
public CollectionUtils() {
}
/**
* Returns a new {@link Collection} containing <tt><i>a</i> - <i>b</i></tt>. The cardinality of each element
* <i>e</i> in the returned {@link Collection} will be the cardinality of <i>e</i> in <i>a</i> minus the cardinality
* of <i>e</i> in <i>b</i>, or zero, whichever is greater.
* <i>e</i> in the returned {@link Collection} will be the cardinality of <i>e</i> in <i>a</i> minus the
* cardinality of <i>e</i> in <i>b</i>, or zero, whichever is greater.
*
* @param a the collection to subtract from, must not be null
* @param b the collection to subtract, must not be null
@ -70,12 +71,12 @@ public class CollectionUtils {
}
return list;
}
/**
* Returns a {@link Map} mapping each unique element in the given {@link Collection} to an {@link Integer}
* representing the number of occurrences of that element in the {@link Collection}.
* <p>
* Only those elements present in the collection will appear as keys in the map.
*
* <p>Only those elements present in the collection will appear as keys in the map.
*
* @param coll the collection to get the cardinality map for, must not be null
* @return the populated cardinality map
@ -84,7 +85,7 @@ public class CollectionUtils {
Map count = new HashMap(coll.size());
for (Iterator it = coll.iterator(); it.hasNext(); ) {
Object obj = it.next();
Integer c = (Integer)(count.get(obj));
Integer c = (Integer) (count.get(obj));
if (c == null) {
count.put(obj, INTEGER_ONE);
} else {
@ -93,12 +94,12 @@ public class CollectionUtils {
}
return count;
}
/**
* Returns <tt>true</tt> iff the given {@link Collection}s contain exactly the same elements with exactly the same
* cardinalities.
* <p>
* That is, iff the cardinality of <i>e</i> in <i>a</i> is equal to the cardinality of <i>e</i> in <i>b</i>, for
*
* <p>That is, iff the cardinality of <i>e</i> in <i>a</i> is equal to the cardinality of <i>e</i> in <i>b</i>, for
* each element <i>e</i> in <i>a</i> or <i>b</i>.
*
* @param a the first collection, must not be null
@ -125,13 +126,13 @@ public class CollectionUtils {
}
}
}
//-----------------------------------------------------------------------
/**
* Null-safe check if the specified collection is empty.
* <p>
* Null returns true.
*
* <p>Null returns true.
*
* @param coll the collection to check, may be null
* @return true if empty or null
@ -140,9 +141,9 @@ public class CollectionUtils {
public static boolean isEmpty(Collection coll) {
return (coll == null || coll.isEmpty());
}
private static int getFreq(final Object obj, final Map freqMap) {
Integer count = (Integer)freqMap.get(obj);
Integer count = (Integer) freqMap.get(obj);
if (count != null) {
return count.intValue();
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.utils;
import java.util.ArrayList;
@ -20,22 +21,25 @@ import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Generic Poller.
*
* @author nkorange
*/
public class GenericPoller<T> implements Poller<T> {
private AtomicInteger index = new AtomicInteger(0);
private final AtomicInteger index = new AtomicInteger(0);
private List<T> items = new ArrayList<T>();
public GenericPoller(List<T> items) {
this.items = items;
}
@Override
public T next() {
return items.get(Math.abs(index.getAndIncrement() % items.size()));
}
@Override
public Poller<T> refresh(List<T> items) {
return new GenericPoller<T>(items);

View File

@ -22,7 +22,10 @@ import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.selector.ExpressionSelector;
import com.alibaba.nacos.api.selector.NoneSelector;
import com.alibaba.nacos.api.selector.SelectorType;
import com.alibaba.nacos.client.utils.*;
import com.alibaba.nacos.client.utils.LogUtils;
import com.alibaba.nacos.client.utils.ParamUtil;
import com.alibaba.nacos.client.utils.TemplateUtils;
import com.alibaba.nacos.client.utils.TenantUtil;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.common.utils.StringUtils;
@ -30,29 +33,29 @@ import java.util.Properties;
import java.util.concurrent.Callable;
/**
* Init utils.
*
* @author liaochuntao
* @author deshao
*/
public class InitUtils {
/**
* Add a difference to the name naming. This method simply initializes the namespace for Naming.
* Config initialization is not the same, so it cannot be reused directly.
* Add a difference to the name naming. This method simply initializes the namespace for Naming. Config
* initialization is not the same, so it cannot be reused directly.
*
* @param properties
* @return
* @param properties properties
* @return namespace
*/
public static String initNamespaceForNaming(Properties properties) {
String tmpNamespace = null;
String isUseCloudNamespaceParsing =
properties.getProperty(PropertyKeyConst.IS_USE_CLOUD_NAMESPACE_PARSING,
String isUseCloudNamespaceParsing = properties.getProperty(PropertyKeyConst.IS_USE_CLOUD_NAMESPACE_PARSING,
System.getProperty(SystemPropertyKeyConst.IS_USE_CLOUD_NAMESPACE_PARSING,
String.valueOf(Constants.DEFAULT_USE_CLOUD_NAMESPACE_PARSING)));
String.valueOf(Constants.DEFAULT_USE_CLOUD_NAMESPACE_PARSING)));
if (Boolean.parseBoolean(isUseCloudNamespaceParsing)) {
tmpNamespace = TenantUtil.getUserTenantForAns();
tmpNamespace = TemplateUtils.stringEmptyAndThenExecute(tmpNamespace, new Callable<String>() {
@Override
@ -62,7 +65,7 @@ public class InitUtils {
return namespace;
}
});
tmpNamespace = TemplateUtils.stringEmptyAndThenExecute(tmpNamespace, new Callable<String>() {
@Override
public String call() {
@ -72,7 +75,7 @@ public class InitUtils {
}
});
}
tmpNamespace = TemplateUtils.stringEmptyAndThenExecute(tmpNamespace, new Callable<String>() {
@Override
public String call() {
@ -81,11 +84,11 @@ public class InitUtils {
return namespace;
}
});
if (StringUtils.isEmpty(tmpNamespace) && properties != null) {
tmpNamespace = properties.getProperty(PropertyKeyConst.NAMESPACE);
}
tmpNamespace = TemplateUtils.stringEmptyAndThenExecute(tmpNamespace, new Callable<String>() {
@Override
public String call() {
@ -94,33 +97,40 @@ public class InitUtils {
});
return tmpNamespace;
}
/**
* Init web root context.
*/
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, new Runnable() {
@Override
public void run() {
UtilAndComs.WEB_CONTEXT = webContext.indexOf("/") > -1 ? webContext
: "/" + webContext;
UtilAndComs.NACOS_URL_BASE = UtilAndComs.WEB_CONTEXT + "/v1/ns";
UtilAndComs.NACOS_URL_INSTANCE = UtilAndComs.NACOS_URL_BASE + "/instance";
UtilAndComs.webContext = webContext.indexOf("/") > -1 ? webContext : "/" + webContext;
UtilAndComs.nacosUrlBase = UtilAndComs.webContext + "/v1/ns";
UtilAndComs.nacosUrlInstance = UtilAndComs.nacosUrlBase + "/instance";
}
});
}
/**
* Init end point.
*
* @param properties properties
* @return end point
*/
public static String initEndpoint(final Properties properties) {
if (properties == null) {
return "";
}
// Whether to enable domain name resolution rules
String isUseEndpointRuleParsing =
properties.getProperty(PropertyKeyConst.IS_USE_ENDPOINT_PARSING_RULE,
String isUseEndpointRuleParsing = properties.getProperty(PropertyKeyConst.IS_USE_ENDPOINT_PARSING_RULE,
System.getProperty(SystemPropertyKeyConst.IS_USE_ENDPOINT_PARSING_RULE,
String.valueOf(ParamUtil.USE_ENDPOINT_PARSING_RULE_DEFAULT_VALUE)));
String.valueOf(ParamUtil.USE_ENDPOINT_PARSING_RULE_DEFAULT_VALUE)));
boolean isUseEndpointParsingRule = Boolean.parseBoolean(isUseEndpointRuleParsing);
String endpointUrl;
if (isUseEndpointParsingRule) {
@ -132,40 +142,42 @@ public class InitUtils {
} else {
endpointUrl = properties.getProperty(PropertyKeyConst.ENDPOINT);
}
if (StringUtils.isBlank(endpointUrl)) {
return "";
}
String endpointPort = TemplateUtils.stringEmptyAndThenExecute(System.getenv(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_PORT), new Callable<String>() {
@Override
public String call() {
return properties.getProperty(PropertyKeyConst.ENDPOINT_PORT);
}
});
String endpointPort = TemplateUtils
.stringEmptyAndThenExecute(System.getenv(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_PORT),
new Callable<String>() {
@Override
public String call() {
return properties.getProperty(PropertyKeyConst.ENDPOINT_PORT);
}
});
endpointPort = TemplateUtils.stringEmptyAndThenExecute(endpointPort, new Callable<String>() {
@Override
public String call() {
return "8080";
}
});
return endpointUrl + ":" + endpointPort;
}
/**
* Register subType for serialization
* Register subType for serialization.
*
* Now these subType implementation class has registered in static code.
* But there are some problem for classloader. The implementation class
* will be loaded when they are used, which will make deserialize
* before register.
* <p>
* Now these subType implementation class has registered in static code. But there are some problem for classloader.
* The implementation class will be loaded when they are used, which will make deserialize before register.
* </p>
*
* 子类实现类中的静态代码串中已经向Jackson进行了注册但是由于classloader的原因只有当
* 该子类被使用的时候才会加载该类这可能会导致Jackson先进性反序列化再注册子类从而导致
* 反序列化失败
* <p>
* 子类实现类中的静态代码串中已经向Jackson进行了注册但是由于classloader的原因只有当 该子类被使用的时候才会加载该类这可能会导致Jackson先进性反序列化再注册子类从而导致 反序列化失败
* </p>
*/
public static void initSerialization() {
// TODO register in implementation class or remove subType

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.utils;
import java.util.Random;
@ -22,43 +23,43 @@ import java.util.Random;
* java.lang.Math#random()} method and its system-wide {@link Random} object.</p>
* <p>
* It does this to allow for a Random class in which the seed is shared between all members of the class - a better name
* would have been SharedSeedRandom.
* would have been SharedSeedRandom.</p>
* <p>
* <b>N.B.</b> the current implementation overrides the methods {@link Random#nextInt(int)} and {@link
* Random#nextLong()} to produce positive numbers ranging from 0 (inclusive) to MAX_VALUE (exclusive).
*
* </p>
* @author unknown
* @version $Id: JVMRandom.java 911986 2010-02-19 21:19:05Z niallp $
* @since 2.0
*/
public final class JvmRandom extends Random {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 1L;
private static final Random SHARED_RANDOM = new Random();
/**
* Ensures that only the parent constructor can call reseed.
*/
private boolean constructed = false;
/**
* Constructs a new instance.
*/
public JvmRandom() {
this.constructed = true;
}
/**
* Unsupported in 2.0.
*
* @param seed ignored
* @throws UnsupportedOperationException
* @throws UnsupportedOperationException unsupported operation exception
*/
@Override
public synchronized void setSeed(long seed) {
@ -66,32 +67,32 @@ public final class JvmRandom extends Random {
throw new UnsupportedOperationException();
}
}
/**
* Unsupported in 2.0.
*
* @return Nothing, this method always throws an UnsupportedOperationException.
* @throws UnsupportedOperationException
* @throws UnsupportedOperationException unsupported operation exception
*/
@Override
public synchronized double nextGaussian() {
throw new UnsupportedOperationException();
}
/**
* Unsupported in 2.0.
*
* @param byteArray ignored
* @throws UnsupportedOperationException
* @throws UnsupportedOperationException unsupported operation exception
*/
@Override
public void nextBytes(byte[] byteArray) {
throw new UnsupportedOperationException();
}
/**
* <p>Returns the next pseudorandom, uniformly distributed int value from the Math.random() sequence.</p> Identical
* to <code>nextInt(Integer.MAX_VALUE)</code> <p> <b>N.B. All values are >= 0.<b> </p>
* to <code>nextInt(Integer.MAX_VALUE)</code> <p> <b>N.B. All values are >= 0.</b> </p>
*
* @return the random int
*/
@ -99,7 +100,7 @@ public final class JvmRandom extends Random {
public int nextInt() {
return nextInt(Integer.MAX_VALUE);
}
/**
* <p>Returns a pseudorandom, uniformly distributed int value between <code>0</code> (inclusive) and the specified
* value (exclusive), from the Math.random() sequence.</p>
@ -112,10 +113,11 @@ public final class JvmRandom extends Random {
public int nextInt(int n) {
return SHARED_RANDOM.nextInt(n);
}
/**
* <p>Returns the next pseudorandom, uniformly distributed long value from the Math.random() sequence.</p> Identical
* to <code>nextLong(Long.MAX_VALUE)</code> <p> <b>N.B. All values are >= 0.<b> </p>
* <p>Returns the next pseudorandom, uniformly distributed long value from the Math.random() sequence.</p>
* Identical
* to <code>nextLong(Long.MAX_VALUE)</code> <p> <b>N.B. All values are >= 0.</b> </p>
*
* @return the random long
*/
@ -123,7 +125,7 @@ public final class JvmRandom extends Random {
public long nextLong() {
return nextLong(Long.MAX_VALUE);
}
/**
* <p>Returns a pseudorandom, uniformly distributed long value between <code>0</code> (inclusive) and the specified
* value (exclusive), from the Math.random() sequence.</p>
@ -134,16 +136,13 @@ public final class JvmRandom extends Random {
*/
public static long nextLong(long n) {
if (n <= 0) {
throw new IllegalArgumentException(
"Upper bound for nextInt must be positive"
);
throw new IllegalArgumentException("Upper bound for nextInt must be positive");
}
// Code adapted from Harmony Random#nextInt(int)
// n is power of 2
if ((n & -n) == n) {
// dropping lower order bits improves behaviour for low values of n
return next63bits() >> 63
- bitsRequired(n - 1);
return next63bits() >> 63 - bitsRequired(n - 1);
}
// Not a power of two
long val;
@ -155,7 +154,7 @@ public final class JvmRandom extends Random {
} while (bits - val + (n - 1) < 0);
return val;
}
/**
* <p>Returns the next pseudorandom, uniformly distributed boolean value from the Math.random() sequence.</p>
*
@ -165,9 +164,10 @@ public final class JvmRandom extends Random {
public boolean nextBoolean() {
return SHARED_RANDOM.nextBoolean();
}
/**
* <p>Returns the next pseudorandom, uniformly distributed float value between <code>0.0</code> and <code>1.0</code>
* <p>Returns the next pseudorandom, uniformly distributed float value between <code>0.0</code> and
* <code>1.0</code>
* from the Math.random() sequence.</p>
*
* @return the random float
@ -176,7 +176,7 @@ public final class JvmRandom extends Random {
public float nextFloat() {
return SHARED_RANDOM.nextFloat();
}
/**
* <p>Synonymous to the Math.random() call.</p>
*
@ -186,9 +186,9 @@ public final class JvmRandom extends Random {
public double nextDouble() {
return SHARED_RANDOM.nextDouble();
}
/**
* Get the next unsigned random long
* Get the next unsigned random long.
*
* @return unsigned random long
*/
@ -196,7 +196,7 @@ public final class JvmRandom extends Random {
// drop the sign bit to leave 63 random bits
return SHARED_RANDOM.nextLong() & 0x7fffffffffffffffL;
}
/**
* Count the number of bits required to represent a long number.
*

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.utils;
import com.alibaba.nacos.common.utils.StringUtils;
@ -21,20 +22,29 @@ import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* Net utils.
*
* @author xuanyin.zy
*/
public class NetUtils {
private static String LOCAL_IP;
private static String localIp;
/**
* Get local ip.
*
* @return local ip
*/
public static String localIP() {
try {
if (!StringUtils.isEmpty(LOCAL_IP)) {
return LOCAL_IP;
if (!StringUtils.isEmpty(localIp)) {
return localIp;
}
String ip = System.getProperty("com.alibaba.nacos.client.naming.local.ip", InetAddress.getLocalHost().getHostAddress());
return LOCAL_IP = ip;
String ip = System.getProperty("com.alibaba.nacos.client.naming.local.ip",
InetAddress.getLocalHost().getHostAddress());
return localIp = ip;
} catch (UnknownHostException e) {
return "resolve_failed";
}

View File

@ -13,25 +13,29 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.utils;
/**
* Pair.
*
* @author nkorange
*/
public class Pair<T> {
private T item;
private double weight;
private final T item;
private final double weight;
public Pair(T item, double weight) {
this.item = item;
this.weight = weight;
}
public T item() {
return item;
}
public double weight() {
return weight;
}

View File

@ -13,23 +13,27 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.utils;
import java.util.List;
/**
* Poller.
*
* @author nkorange
*/
public interface Poller<T> {
/**
* Get next element selected by poller
* Get next element selected by poller.
*
* @return next element
*/
T next();
/**
* Update items stored in poller
* Update items stored in poller.
*
* @param items new item list
* @return new poller instance

View File

@ -13,12 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.utils;
import java.util.Random;
/**
* <p><code>RandomUtils</code> is a wrapper that supports all possible {@link java.util.Random} methods via the {@link
* <code>RandomUtils</code> is a wrapper that supports all possible {@link java.util.Random} methods via the {@link
* java.lang.Math#random()} method and its system-wide <code>Random</code> object.
*
* @author Gary D. Gregory
@ -26,27 +27,27 @@ import java.util.Random;
* @since 2.0
*/
public class RandomUtils {
/**
* An instance of {@link JvmRandom}.
*/
private static final Random JVM_RANDOM = new JvmRandom();
// should be possible for JVM_RANDOM?
// public static void nextBytes(byte[]) {
// public synchronized double nextGaussian();
// }
/**
* <p>Returns the next pseudorandom, uniformly distributed int value from the Math.random() sequence.</p> <b>N.B.
* All values are >= 0.<b>
* All values are >= 0.</b>
*
* @return the random int
*/
public static int nextInt() {
return nextInt(JVM_RANDOM);
}
/**
* <p>Returns the next pseudorandom, uniformly distributed int value from the given <code>random</code>
* sequence.</p>
@ -57,7 +58,7 @@ public class RandomUtils {
public static int nextInt(Random random) {
return random.nextInt();
}
/**
* <p>Returns a pseudorandom, uniformly distributed int value between <code>0</code> (inclusive) and the specified
* value (exclusive), from the Math.random() sequence.</p>
@ -68,7 +69,7 @@ public class RandomUtils {
public static int nextInt(int n) {
return nextInt(JVM_RANDOM, n);
}
/**
* <p>Returns a pseudorandom, uniformly distributed int value between <code>0</code> (inclusive) and the specified
* value (exclusive), from the given Random sequence.</p>
@ -81,17 +82,17 @@ public class RandomUtils {
// check this cannot return 'n'
return random.nextInt(n);
}
/**
* <p>Returns the next pseudorandom, uniformly distributed long value from the Math.random() sequence.</p> <b>N.B.
* All values are >= 0.<b>
* All values are >= 0.</b>
*
* @return the random long
*/
public static long nextLong() {
return nextLong(JVM_RANDOM);
}
/**
* <p>Returns the next pseudorandom, uniformly distributed long value from the given Random sequence.</p>
*
@ -101,7 +102,7 @@ public class RandomUtils {
public static long nextLong(Random random) {
return random.nextLong();
}
/**
* <p>Returns the next pseudorandom, uniformly distributed boolean value from the Math.random() sequence.</p>
*
@ -110,7 +111,7 @@ public class RandomUtils {
public static boolean nextBoolean() {
return nextBoolean(JVM_RANDOM);
}
/**
* <p>Returns the next pseudorandom, uniformly distributed boolean value from the given random sequence.</p>
*
@ -120,9 +121,10 @@ public class RandomUtils {
public static boolean nextBoolean(Random random) {
return random.nextBoolean();
}
/**
* <p>Returns the next pseudorandom, uniformly distributed float value between <code>0.0</code> and <code>1.0</code>
* <p>Returns the next pseudorandom, uniformly distributed float value between <code>0.0</code> and
* <code>1.0</code>
* from the Math.random() sequence.</p>
*
* @return the random float
@ -130,9 +132,10 @@ public class RandomUtils {
public static float nextFloat() {
return nextFloat(JVM_RANDOM);
}
/**
* <p>Returns the next pseudorandom, uniformly distributed float value between <code>0.0</code> and <code>1.0</code>
* <p>Returns the next pseudorandom, uniformly distributed float value between <code>0.0</code> and
* <code>1.0</code>
* from the given Random sequence.</p>
*
* @param random the Random sequence generator.
@ -141,9 +144,10 @@ public class RandomUtils {
public static float nextFloat(Random random) {
return random.nextFloat();
}
/**
* <p>Returns the next pseudorandom, uniformly distributed float value between <code>0.0</code> and <code>1.0</code>
* <p>Returns the next pseudorandom, uniformly distributed float value between <code>0.0</code> and
* <code>1.0</code>
* from the Math.random() sequence.</p>
*
* @return the random double
@ -151,9 +155,10 @@ public class RandomUtils {
public static double nextDouble() {
return nextDouble(JVM_RANDOM);
}
/**
* <p>Returns the next pseudorandom, uniformly distributed float value between <code>0.0</code> and <code>1.0</code>
* <p>Returns the next pseudorandom, uniformly distributed float value between <code>0.0</code> and
* <code>1.0</code>
* from the given Random sequence.</p>
*
* @param random the Random sequence generator.
@ -162,5 +167,5 @@ public class RandomUtils {
public static double nextDouble(Random random) {
return random.nextDouble();
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.utils;
import com.alibaba.nacos.client.identify.Base64;
@ -20,46 +21,52 @@ import com.alibaba.nacos.client.identify.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/**
* Sign util.
*
* @author pbting
* @date 2019-01-22 10:20 PM
*/
public class SignUtil {
public static final Charset UTF8 = Charset.forName("UTF-8");
public static final Charset UTF8 = StandardCharsets.UTF_8;
public SignUtil() {
}
/**
* Sign.
*
* @param data data
* @param key key
* @return signature
* @throws Exception exception
*/
public static String sign(String data, String key) throws Exception {
try {
byte[] signature = sign(data.getBytes(UTF8), key.getBytes(UTF8),
SignUtil.SigningAlgorithm.HmacSHA1);
byte[] signature = sign(data.getBytes(UTF8), key.getBytes(UTF8), SignUtil.SigningAlgorithm.HmacSHA1);
return new String(Base64.encodeBase64(signature));
} catch (Exception var3) {
throw new Exception(
"Unable to calculate a request signature: " + var3.getMessage(),
var3);
} catch (Exception ex) {
throw new Exception("Unable to calculate a request signature: " + ex.getMessage(), ex);
}
}
private static byte[] sign(byte[] data, byte[] key,
SignUtil.SigningAlgorithm algorithm) throws Exception {
private static byte[] sign(byte[] data, byte[] key, SignUtil.SigningAlgorithm algorithm) throws Exception {
try {
Mac mac = Mac.getInstance(algorithm.toString());
mac.init(new SecretKeySpec(key, algorithm.toString()));
return mac.doFinal(data);
} catch (Exception var4) {
throw new Exception(
"Unable to calculate a request signature: " + var4.getMessage(),
var4);
} catch (Exception ex) {
throw new Exception("Unable to calculate a request signature: " + ex.getMessage(), ex);
}
}
public enum SigningAlgorithm {
// Hmac SHA1 algorithm
HmacSHA1;
SigningAlgorithm() {
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.utils;
import java.security.SecureRandom;
@ -30,27 +31,26 @@ import java.util.concurrent.atomic.AtomicLong;
* ThreadLocalRandom} is particularly appropriate when multiple tasks (for example, each a {@link
* io.netty.util.internal.chmv8.ForkJoinTask}) use random numbers in parallel in thread pools.
* <p>
* <p>
* Usages of this class should typically be of the form: {@code ThreadLocalRandom.current().nextX(...)} (where {@code X}
* is {@code Int}, {@code Long}, etc). When all usages are of this form, it is never possible to accidently share a
* {@code ThreadLocalRandom} across multiple threads.
* <p>
* </p>
* <p>
* This class also provides additional commonly used bounded random generation methods.
* <p>
* </p>
* //since 1.7 //author Doug Lea
*/
@SuppressWarnings("all")
public class ThreadLocalRandom extends Random {
private static final AtomicLong seedUniquifier = new AtomicLong();
private static volatile long initialSeedUniquifier;
public static void setInitialSeedUniquifier(long initialSeedUniquifier) {
ThreadLocalRandom.initialSeedUniquifier = initialSeedUniquifier;
}
public static synchronized long getInitialSeedUniquifier() {
// Use the value set via the setter.
long initialSeedUniquifier = ThreadLocalRandom.initialSeedUniquifier;
@ -67,7 +67,7 @@ public class ThreadLocalRandom extends Random {
}
};
generatorThread.start();
// Get the random seed from the thread with timeout.
final long timeoutSeconds = 3;
final long deadLine = System.nanoTime() + TimeUnit.SECONDS.toNanos(timeoutSeconds);
@ -76,7 +76,7 @@ public class ThreadLocalRandom extends Random {
if (waitTime <= 0) {
break;
}
try {
Long result = queue.poll(waitTime, TimeUnit.NANOSECONDS);
if (result != null) {
@ -87,53 +87,55 @@ public class ThreadLocalRandom extends Random {
// Ignore
}
}
// Just in case the initialSeedUniquifier is zero or some other constant
initialSeedUniquifier ^= 0x3255ecdc33bae119L; // just a meaningless random number
initialSeedUniquifier ^= Long.reverse(System.nanoTime());
ThreadLocalRandom.initialSeedUniquifier = initialSeedUniquifier;
}
return initialSeedUniquifier;
}
private static long newSeed() {
for (; ; ) {
final long current = seedUniquifier.get();
final long actualCurrent = current != 0 ? current : getInitialSeedUniquifier();
// L'Ecuyer, "Tables of Linear Congruential Generators of Different Sizes and Good Lattice Structure", 1999
final long next = actualCurrent * 181783497276652981L;
if (seedUniquifier.compareAndSet(current, next)) {
return next ^ System.nanoTime();
}
}
}
// same constants as Random, but must be redeclared because private
private static final long multiplier = 0x5DEECE66DL;
private static final long addend = 0xBL;
private static final long mask = (1L << 48) - 1;
/**
* The random seed. We can't use super.seed.
*/
private long rnd;
/**
* Initialization flag to permit calls to setSeed to succeed only while executing the Random constructor. We can't
* allow others since it would cause setting seed in one part of a program to unintentionally impact other usages by
* the thread.
*/
boolean initialized = false;
// Padding to help avoid memory contention among seed updates in
// different TLRs in the common case that they are located near
// each other.
private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7;
/**
* Constructor called only by localRandom.initialValue.
*/
@ -141,7 +143,7 @@ public class ThreadLocalRandom extends Random {
super(newSeed());
initialized = true;
}
/**
* The actual ThreadLocal
*/
@ -151,7 +153,7 @@ public class ThreadLocalRandom extends Random {
return new ThreadLocalRandom();
}
};
/**
* Returns the current thread's {@code ThreadLocalRandom}.
*
@ -160,7 +162,7 @@ public class ThreadLocalRandom extends Random {
public static ThreadLocalRandom current() {
return localRandom.get();
}
/**
* Throws {@code UnsupportedOperationException}. Setting seeds in this generator is not supported.
*
@ -173,13 +175,13 @@ public class ThreadLocalRandom extends Random {
}
rnd = (seed ^ multiplier) & mask;
}
@Override
protected int next(int bits) {
rnd = (rnd * multiplier + addend) & mask;
return (int)(rnd >>> (48 - bits));
return (int) (rnd >>> (48 - bits));
}
/**
* Returns a pseudorandom, uniformly distributed value between the given least value (inclusive) and bound
* (exclusive).
@ -195,7 +197,7 @@ public class ThreadLocalRandom extends Random {
}
return nextInt(bound - least) + least;
}
/**
* Returns a pseudorandom, uniformly distributed value between 0 (inclusive) and the specified value (exclusive).
*
@ -207,7 +209,7 @@ public class ThreadLocalRandom extends Random {
if (n <= 0) {
throw new IllegalArgumentException("n must be positive");
}
// Divide n by two until small enough for nextInt. On each
// iteration (at most 31 of them but usually much less),
// randomly choose both whether to include high bit in result
@ -223,9 +225,9 @@ public class ThreadLocalRandom extends Random {
}
n = nextn;
}
return offset + nextInt((int)n);
return offset + nextInt((int) n);
}
/**
* Returns a pseudorandom, uniformly distributed value between the given least value (inclusive) and bound
* (exclusive).
@ -241,7 +243,7 @@ public class ThreadLocalRandom extends Random {
}
return nextLong(bound - least) + least;
}
/**
* Returns a pseudorandom, uniformly distributed {@code double} value between 0 (inclusive) and the specified value
* (exclusive).
@ -256,7 +258,7 @@ public class ThreadLocalRandom extends Random {
}
return nextDouble() * n;
}
/**
* Returns a pseudorandom, uniformly distributed value between the given least value (inclusive) and bound
* (exclusive).
@ -272,6 +274,6 @@ public class ThreadLocalRandom extends Random {
}
return nextDouble() * (bound - least) + least;
}
private static final long serialVersionUID = -5851777807851030925L;
}

View File

@ -13,53 +13,54 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.naming.utils;
import com.alibaba.nacos.common.utils.VersionUtils;
/**
* Util and constants.
*
* @author xuanyin.zy
*/
public class UtilAndComs {
public static final String VERSION = "Nacos-Java-Client:v" + VersionUtils.version;
public static String WEB_CONTEXT = "/nacos";
public static String NACOS_URL_BASE = WEB_CONTEXT + "/v1/ns";
public static String NACOS_URL_INSTANCE = NACOS_URL_BASE + "/instance";
public static String NACOS_URL_SERVICE = NACOS_URL_BASE + "/service";
public static String webContext = "/nacos";
public static String nacosUrlBase = webContext + "/v1/ns";
public static String nacosUrlInstance = nacosUrlBase + "/instance";
public static String nacosUrlService = nacosUrlBase + "/service";
public static final String ENCODING = "UTF-8";
public static final String ENV_LIST_KEY = "envList";
public static final String ALL_IPS = "000--00-ALL_IPS--00--000";
public static final String FAILOVER_SWITCH = "00-00---000-VIPSRV_FAILOVER_SWITCH-000---00-00";
public static final String DEFAULT_NAMESPACE_ID = "public";
public static final int REQUEST_DOMAIN_RETRY_COUNT = 3;
public static final String NACOS_NAMING_LOG_NAME = "com.alibaba.nacos.naming.log.filename";
public static final String NACOS_NAMING_LOG_LEVEL = "com.alibaba.nacos.naming.log.level";
public static final String SERVER_ADDR_IP_SPLITER = ":";
public static final int DEFAULT_CLIENT_BEAT_THREAD_COUNT = Runtime.getRuntime()
.availableProcessors() > 1 ? Runtime.getRuntime().availableProcessors() / 2
: 1;
public static final int DEFAULT_POLLING_THREAD_COUNT = Runtime.getRuntime()
.availableProcessors() > 1 ? Runtime.getRuntime().availableProcessors() / 2
: 1;
public static final int DEFAULT_CLIENT_BEAT_THREAD_COUNT =
Runtime.getRuntime().availableProcessors() > 1 ? Runtime.getRuntime().availableProcessors() / 2 : 1;
public static final int DEFAULT_POLLING_THREAD_COUNT =
Runtime.getRuntime().availableProcessors() > 1 ? Runtime.getRuntime().availableProcessors() / 2 : 1;
public static final String HTTP = "http://";
public static final String HTTPS = "https://";
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.security;
import com.alibaba.nacos.api.PropertyKeyConst;
@ -24,7 +25,6 @@ import com.alibaba.nacos.common.http.param.Header;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.fasterxml.jackson.databind.JsonNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -35,53 +35,53 @@ import java.util.Properties;
import java.util.concurrent.TimeUnit;
/**
* Security proxy to update security information
* Security proxy to update security information.
*
* @author nkorange
* @since 1.2.0
*/
public class SecurityProxy {
private static final Logger SECURITY_LOGGER = LoggerFactory.getLogger(SecurityProxy.class);
private static final String LOGIN_URL = "/v1/auth/users/login";
private NacosRestTemplate nacosRestTemplate = NamingHttpClientManager.getNacosRestTemplate();
private final NacosRestTemplate nacosRestTemplate = NamingHttpClientManager.getInstance().getNacosRestTemplate();
private String contextPath;
/**
* User's name
* User's name.
*/
private String username;
private final String username;
/**
* User's password
* User's password.
*/
private String password;
private final String password;
/**
* A token to take with when sending request to Nacos server
* A token to take with when sending request to Nacos server.
*/
private String accessToken;
/**
* TTL of token in seconds
* TTL of token in seconds.
*/
private long tokenTtl;
/**
* Last timestamp refresh security info from server
* Last timestamp refresh security info from server.
*/
private long lastRefreshTime;
/**
* time window to refresh security info in seconds
* time window to refresh security info in seconds.
*/
private long tokenRefreshWindow;
/**
* Construct from properties, keeping flexibility
* Construct from properties, keeping flexibility.
*
* @param properties a bunch of properties to read
*/
@ -91,14 +91,21 @@ public class SecurityProxy {
contextPath = properties.getProperty(PropertyKeyConst.CONTEXT_PATH, "/nacos");
contextPath = contextPath.startsWith("/") ? contextPath : "/" + contextPath;
}
/**
* Login to servers.
*
* @param servers server list
* @return true if login successfully
*/
public boolean login(List<String> servers) {
try {
if ((System.currentTimeMillis() - lastRefreshTime) < TimeUnit.SECONDS.toMillis(tokenTtl - tokenRefreshWindow)) {
if ((System.currentTimeMillis() - lastRefreshTime) < TimeUnit.SECONDS
.toMillis(tokenTtl - tokenRefreshWindow)) {
return true;
}
for (String server : servers) {
if (login(server)) {
lastRefreshTime = System.currentTimeMillis();
@ -107,24 +114,31 @@ public class SecurityProxy {
}
} catch (Throwable ignore) {
}
return false;
}
/**
* Login to server.
*
* @param server server address
* @return true if login successfully
*/
public boolean login(String server) {
if (StringUtils.isNotBlank(username)) {
Map<String, String> params = new HashMap<String, String>(2);
Map<String, String> bodyMap = new HashMap<>(2);
Map<String, String> bodyMap = new HashMap<String, String>(2);
params.put("username", username);
bodyMap.put("password", password);
String url = "http://" + server + contextPath + LOGIN_URL;
if (server.contains(Constants.HTTP_PREFIX)) {
url = server + contextPath + LOGIN_URL;
}
try {
HttpRestResult<String> restResult = nacosRestTemplate.postForm(url, Header.EMPTY, params, bodyMap, String.class);
HttpRestResult<String> restResult = nacosRestTemplate
.postForm(url, Header.EMPTY, params, bodyMap, String.class);
if (!restResult.ok()) {
SECURITY_LOGGER.error("login failed: {}", JacksonUtils.toJson(restResult));
return false;
@ -136,14 +150,14 @@ public class SecurityProxy {
tokenRefreshWindow = tokenTtl / 10;
}
} catch (Exception e) {
SECURITY_LOGGER.error("[SecurityProxy] login http request failed" +
" url: {}, params: {}, bodyMap: {}, errorMsg: {}", url, params, bodyMap, e.getMessage());
SECURITY_LOGGER.error("[SecurityProxy] login http request failed"
+ " url: {}, params: {}, bodyMap: {}, errorMsg: {}", url, params, bodyMap, e.getMessage());
return false;
}
}
return true;
}
public String getAccessToken() {
return accessToken;
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.utils;
import com.alibaba.nacos.common.utils.StringUtils;
@ -20,43 +21,50 @@ import com.alibaba.nacos.common.utils.StringUtils;
import java.io.File;
/**
* appName util
* appName util.
*
* @author Nacos
*/
public class AppNameUtils {
private static final String PARAM_MARKING_PROJECT = "project.name";
private static final String PARAM_MARKING_JBOSS = "jboss.server.home.dir";
private static final String PARAM_MARKING_JETTY = "jetty.home";
private static final String PARAM_MARKING_TOMCAT = "catalina.base";
private static final String LINUX_ADMIN_HOME = "/home/admin/";
private static final String SERVER_JBOSS = "jboss";
private static final String SERVER_JETTY = "jetty";
private static final String SERVER_TOMCAT = "tomcat";
private static final String SERVER_UNKNOWN = "unknown server";
public static String getAppName() {
String appName = null;
appName = getAppNameByProjectName();
if (appName != null) {
return appName;
}
appName = getAppNameByServerHome();
if (appName != null) {
return appName;
}
return "unknown";
}
private static String getAppNameByProjectName() {
return System.getProperty(PARAM_MARKING_PROJECT);
}
private static String getAppNameByServerHome() {
String serverHome = null;
if (SERVER_JBOSS.equals(getServerType())) {
@ -66,14 +74,14 @@ public class AppNameUtils {
} else if (SERVER_TOMCAT.equals(getServerType())) {
serverHome = System.getProperty(PARAM_MARKING_TOMCAT);
}
if (serverHome != null && serverHome.startsWith(LINUX_ADMIN_HOME)) {
return StringUtils.substringBetween(serverHome, LINUX_ADMIN_HOME, File.separator);
}
return null;
}
private static String getServerType() {
String serverType = null;
if (System.getProperty(PARAM_MARKING_JBOSS) != null) {
@ -87,5 +95,5 @@ public class AppNameUtils {
}
return serverType;
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.utils;
import org.slf4j.Logger;
@ -26,9 +27,9 @@ import java.util.Map;
* @author Nacos
*/
public class EnvUtil {
final static public Logger LOGGER = LogUtils.logger(EnvUtil.class);
public static final Logger LOGGER = LogUtils.logger(EnvUtil.class);
public static void setSelfEnv(Map<String, List<String>> headers) {
if (headers != null) {
List<String> amorayTagTmp = headers.get(AMORY_TAG);
@ -44,7 +45,7 @@ public class EnvUtil {
LOGGER.warn("selfAmoryTag:{}", selfAmorayTag);
}
}
List<String> vipserverTagTmp = headers.get(VIPSERVER_TAG);
if (vipserverTagTmp == null) {
if (selfVipserverTag != null) {
@ -73,19 +74,19 @@ public class EnvUtil {
}
}
}
public static String getSelfAmorayTag() {
return selfAmorayTag;
}
public static String getSelfVipserverTag() {
return selfVipserverTag;
}
public static String getSelfLocationTag() {
return selfLocationTag;
}
private static String listToString(List<String> list) {
if (list == null || list.isEmpty()) {
return null;
@ -97,11 +98,16 @@ public class EnvUtil {
}
return result.toString().substring(0, result.length() - 1);
}
private static String selfAmorayTag;
private static String selfVipserverTag;
private static String selfLocationTag;
private final static String AMORY_TAG = "Amory-Tag";
private final static String VIPSERVER_TAG = "Vipserver-Tag";
private final static String LOCATION_TAG = "Location-Tag";
private static final String AMORY_TAG = "Amory-Tag";
private static final String VIPSERVER_TAG = "Vipserver-Tag";
private static final String LOCATION_TAG = "Location-Tag";
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.utils;
import com.alibaba.nacos.common.utils.StringUtils;
@ -21,24 +22,25 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* ip tool
* ip tool.
*
* @author Nacos
*/
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
public class IPUtil {
private static final Pattern IPV4_PATTERN = Pattern.compile("^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$");
public class IpUtil {
private static final Pattern IPV4_PATTERN = Pattern
.compile("^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$");
private static final Pattern IPV6_PATTERN = Pattern.compile("^([\\da-fA-F]{1,4}:){7}[\\da-fA-F]{1,4}$");
public static boolean isIPV4(String addr) {
public static boolean isIpv4(String addr) {
return isMatch(addr, IPV4_PATTERN);
}
public static boolean isIPV6(String addr) {
public static boolean isIpv6(String addr) {
return isMatch(addr, IPV6_PATTERN);
}
private static boolean isMatch(String data, Pattern pattern) {
if (StringUtils.isBlank(data)) {
return false;

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.utils;
import com.alibaba.nacos.client.logging.AbstractNacosLogging;
@ -23,18 +24,20 @@ import org.slf4j.Logger;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Log utils.
*
* @author <a href="mailto:huangxiaoyu1018@gmail.com">hxy1991</a>
* @since 0.9.0
*/
public class LogUtils {
public static final Logger NAMING_LOGGER;
static {
try {
boolean isLogback = false;
AbstractNacosLogging nacosLogging;
try {
Class.forName("ch.qos.logback.classic.Logger");
nacosLogging = new LogbackNacosLogging();
@ -42,27 +45,27 @@ public class LogUtils {
} catch (ClassNotFoundException e) {
nacosLogging = new Log4J2NacosLogging();
}
try {
nacosLogging.loadConfiguration();
} catch (Throwable t) {
if (isLogback) {
getLogger(LogUtils.class).warn("Load Logback Configuration of Nacos fail, message: {}",
t.getMessage());
getLogger(LogUtils.class)
.warn("Load Logback Configuration of Nacos fail, message: {}", t.getMessage());
} else {
getLogger(LogUtils.class).warn("Load Log4j Configuration of Nacos fail, message: {}",
t.getMessage());
getLogger(LogUtils.class)
.warn("Load Log4j Configuration of Nacos fail, message: {}", t.getMessage());
}
}
} catch (Throwable t1) {
getLogger(LogUtils.class).warn("Init Nacos Logging fail, message: {}", t1.getMessage());
} catch (Throwable ex) {
getLogger(LogUtils.class).warn("Init Nacos Logging fail, message: {}", ex.getMessage());
}
NAMING_LOGGER = getLogger("com.alibaba.nacos.client.naming");
}
public static Logger logger(Class<?> clazz) {
return getLogger(clazz);
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.utils;
import com.alibaba.nacos.api.PropertyKeyConst;
@ -28,39 +29,47 @@ import java.util.concurrent.Callable;
import java.util.regex.Pattern;
/**
* manage param tool
* manage param tool.
*
* @author nacos
*/
public class ParamUtil {
private final static Logger LOGGER = LogUtils.logger(ParamUtil.class);
public final static boolean USE_ENDPOINT_PARSING_RULE_DEFAULT_VALUE = true;
private static final Logger LOGGER = LogUtils.logger(ParamUtil.class);
public static final boolean USE_ENDPOINT_PARSING_RULE_DEFAULT_VALUE = true;
private static final Pattern PATTERN = Pattern.compile("\\$\\{[^}]+\\}");
private static String defaultContextPath;
private static String defaultNodesPath = "serverlist";
private static String appKey;
private static String appName;
private static String defaultServerPort;
private static final String DEFAULT_SERVER_PORT;
private static String clientVersion = "unknown";
private static int connectTimeout;
private static double perTaskConfigSize = 3000;
static {
// 客户端身份信息
appKey = System.getProperty("nacos.client.appKey", "");
defaultContextPath = System.getProperty("nacos.client.contextPath", "nacos");
appName = AppNameUtils.getAppName();
String defaultServerPortTmp = "8848";
defaultServerPort = System.getProperty("nacos.server.port", defaultServerPortTmp);
LOGGER.info("[settings] [req-serv] nacos-server port:{}", defaultServerPort);
DEFAULT_SERVER_PORT = System.getProperty("nacos.server.port", defaultServerPortTmp);
LOGGER.info("[settings] [req-serv] nacos-server port:{}", DEFAULT_SERVER_PORT);
String tmp = "1000";
try {
tmp = System.getProperty("NACOS.CONNECT.TIMEOUT", "1000");
@ -71,10 +80,9 @@ public class ParamUtil {
throw new IllegalArgumentException(msg, e);
}
LOGGER.info("[settings] [http-client] connect timeout:{}", connectTimeout);
try {
InputStream in = HttpSimpleClient.class.getClassLoader()
.getResourceAsStream("application.properties");
InputStream in = HttpSimpleClient.class.getClassLoader().getResourceAsStream("application.properties");
Properties props = new Properties();
props.load(in);
String val = null;
@ -86,7 +94,7 @@ public class ParamUtil {
} catch (Exception e) {
LOGGER.error("[500] read application.properties", e);
}
try {
perTaskConfigSize = Double.valueOf(System.getProperty("PER_TASK_CONFIG_SIZE", "3000"));
LOGGER.info("PER_TASK_CONFIG_SIZE: {}", perTaskConfigSize);
@ -94,75 +102,80 @@ public class ParamUtil {
LOGGER.error("[PER_TASK_CONFIG_SIZE] PER_TASK_CONFIG_SIZE invalid", t);
}
}
public static String getAppKey() {
return appKey;
}
public static void setAppKey(String appKey) {
ParamUtil.appKey = appKey;
}
public static String getAppName() {
return appName;
}
public static void setAppName(String appName) {
ParamUtil.appName = appName;
}
public static String getDefaultContextPath() {
return defaultContextPath;
}
public static void setDefaultContextPath(String defaultContextPath) {
ParamUtil.defaultContextPath = defaultContextPath;
}
public static String getClientVersion() {
return clientVersion;
}
public static void setClientVersion(String clientVersion) {
ParamUtil.clientVersion = clientVersion;
}
public static int getConnectTimeout() {
return connectTimeout;
}
public static void setConnectTimeout(int connectTimeout) {
ParamUtil.connectTimeout = connectTimeout;
}
public static double getPerTaskConfigSize() {
return perTaskConfigSize;
}
public static void setPerTaskConfigSize(double perTaskConfigSize) {
ParamUtil.perTaskConfigSize = perTaskConfigSize;
}
public static String getDefaultServerPort() {
return defaultServerPort;
return DEFAULT_SERVER_PORT;
}
public static String getDefaultNodesPath() {
return defaultNodesPath;
}
public static void setDefaultNodesPath(String defaultNodesPath) {
ParamUtil.defaultNodesPath = defaultNodesPath;
}
/**
* Parse namespace from properties and environment.
*
* @param properties properties
* @return namespace
*/
public static String parseNamespace(Properties properties) {
String namespaceTmp = null;
String isUseCloudNamespaceParsing =
properties.getProperty(PropertyKeyConst.IS_USE_CLOUD_NAMESPACE_PARSING,
String isUseCloudNamespaceParsing = properties.getProperty(PropertyKeyConst.IS_USE_CLOUD_NAMESPACE_PARSING,
System.getProperty(SystemPropertyKeyConst.IS_USE_CLOUD_NAMESPACE_PARSING,
String.valueOf(Constants.DEFAULT_USE_CLOUD_NAMESPACE_PARSING)));
String.valueOf(Constants.DEFAULT_USE_CLOUD_NAMESPACE_PARSING)));
if (Boolean.parseBoolean(isUseCloudNamespaceParsing)) {
namespaceTmp = TemplateUtils.stringBlankAndThenExecute(namespaceTmp, new Callable<String>() {
@Override
@ -170,7 +183,7 @@ public class ParamUtil {
return TenantUtil.getUserTenantForAcm();
}
});
namespaceTmp = TemplateUtils.stringBlankAndThenExecute(namespaceTmp, new Callable<String>() {
@Override
public String call() {
@ -179,44 +192,48 @@ public class ParamUtil {
}
});
}
if (StringUtils.isBlank(namespaceTmp)) {
namespaceTmp = properties.getProperty(PropertyKeyConst.NAMESPACE);
}
return StringUtils.isNotBlank(namespaceTmp) ? namespaceTmp.trim() : StringUtils.EMPTY;
}
/**
* Parse end point rule.
*
* @param endpointUrl endpoint url
* @return end point rule
*/
public static String parsingEndpointRule(String endpointUrl) {
// 配置文件中输入的话 ENV 中的优先
if (endpointUrl == null
|| !PATTERN.matcher(endpointUrl).find()) {
if (endpointUrl == null || !PATTERN.matcher(endpointUrl).find()) {
// skip retrieve from system property and retrieve directly from system env
String endpointUrlSource = System.getenv(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_URL);
if (StringUtils.isNotBlank(endpointUrlSource)) {
endpointUrl = endpointUrlSource;
}
return StringUtils.isNotBlank(endpointUrl) ? endpointUrl : "";
}
endpointUrl = endpointUrl.substring(endpointUrl.indexOf("${") + 2,
endpointUrl.lastIndexOf("}"));
endpointUrl = endpointUrl.substring(endpointUrl.indexOf("${") + 2, endpointUrl.lastIndexOf("}"));
int defStartOf = endpointUrl.indexOf(":");
String defaultEndpointUrl = null;
if (defStartOf != -1) {
defaultEndpointUrl = endpointUrl.substring(defStartOf + 1);
endpointUrl = endpointUrl.substring(0, defStartOf);
}
String endpointUrlSource = TemplateUtils.stringBlankAndThenExecute(System.getProperty(endpointUrl,
System.getenv(endpointUrl)), new Callable<String>() {
@Override
public String call() {
return System.getenv(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_URL);
}
});
String endpointUrlSource = TemplateUtils
.stringBlankAndThenExecute(System.getProperty(endpointUrl, System.getenv(endpointUrl)),
new Callable<String>() {
@Override
public String call() {
return System.getenv(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_URL);
}
});
if (StringUtils.isBlank(endpointUrlSource)) {
if (StringUtils.isNotBlank(defaultEndpointUrl)) {
endpointUrl = defaultEndpointUrl;
@ -224,7 +241,7 @@ public class ParamUtil {
} else {
endpointUrl = endpointUrlSource;
}
return StringUtils.isNotBlank(endpointUrl) ? endpointUrl : "";
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.utils;
import com.alibaba.nacos.common.utils.StringUtils;
@ -20,15 +21,23 @@ import com.alibaba.nacos.common.utils.StringUtils;
import java.util.concurrent.Callable;
/**
* Template Utils.
*
* @author pbting
* @date 2019-03-04 1:31 PM
*/
public class TemplateUtils {
/**
* Execute if string not empty.
*
* @param source source
* @param runnable execute runnable
*/
public static void stringNotEmptyAndThenExecute(String source, Runnable runnable) {
if (StringUtils.isNotEmpty(source)) {
try {
runnable.run();
} catch (Exception e) {
@ -36,32 +45,46 @@ public class TemplateUtils {
}
}
}
/**
* Execute if string empty.
*
* @param source empty source
* @param callable execute callable
* @return result
*/
public static String stringEmptyAndThenExecute(String source, Callable<String> callable) {
if (StringUtils.isEmpty(source)) {
try {
return callable.call();
} catch (Exception e) {
LogUtils.NAMING_LOGGER.error("string empty and then execute cause an exception.", e);
}
}
return source.trim();
}
/**
* Execute if string blank.
*
* @param source empty source
* @param callable execute callable
* @return result
*/
public static String stringBlankAndThenExecute(String source, Callable<String> callable) {
if (StringUtils.isBlank(source)) {
try {
return callable.call();
} catch (Exception e) {
LogUtils.NAMING_LOGGER.error("string empty and then execute cause an exception.", e);
}
}
return source.trim();
}
}

View File

@ -13,51 +13,52 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.utils;
import com.alibaba.nacos.common.utils.StringUtils;
/**
* Tenant Util
* Tenant Util.
*
* @author Nacos
*/
public class TenantUtil {
private static String userTenant;
private static final String USER_TENANT;
static {
userTenant = System.getProperty("tenant.id", "");
USER_TENANT = System.getProperty("tenant.id", "");
}
/**
* Adapt the way ACM gets tenant on the cloud.
* <p>
* Note the difference between getting and getting ANS.
* Since the processing logic on the server side is different, the default value returns differently.
* Note the difference between getting and getting ANS. Since the processing logic on the server side is different,
* the default value returns differently.
* </p>
*
* @return
* @return user tenant for acm
*/
public static String getUserTenantForAcm() {
String tmp = userTenant;
if (StringUtils.isBlank(userTenant)) {
String tmp = USER_TENANT;
if (StringUtils.isBlank(USER_TENANT)) {
tmp = System.getProperty("acm.namespace", "");
}
return tmp;
}
/**
* Adapt the way ANS gets tenant on the cloud.
*
* @return
* @return user tenant for ans
*/
public static String getUserTenantForAns() {
String tmp = userTenant;
if (StringUtils.isBlank(userTenant)) {
String tmp = USER_TENANT;
if (StringUtils.isBlank(USER_TENANT)) {
tmp = System.getProperty("ans.namespace");
}
return tmp;

View File

@ -18,34 +18,37 @@ package com.alibaba.nacos.client.utils;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.common.utils.StringUtils;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* All parameter validation tools
* All parameter validation tools.
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
*/
@SuppressWarnings("all")
public final class ValidatorUtils {
private static final Pattern CONTEXT_PATH_MATCH = Pattern.compile("(\\/)\\1+");
public static void checkInitParam(Properties properties) throws NacosException {
checkContextPath(properties.getProperty(PropertyKeyConst.CONTEXT_PATH));
}
public static void checkContextPath(String contextPath) {
if (contextPath == null) {
return;
}
Matcher matcher = CONTEXT_PATH_MATCH.matcher(contextPath);
if (matcher.find()) {
throw new IllegalArgumentException("Illegal url path expression");
}
}
private static final Pattern CONTEXT_PATH_MATCH = Pattern.compile("(\\/)\\1+");
public static void checkInitParam(Properties properties) throws NacosException {
checkContextPath(properties.getProperty(PropertyKeyConst.CONTEXT_PATH));
}
/**
* Check context path.
*
* @param contextPath context path
*/
public static void checkContextPath(String contextPath) {
if (contextPath == null) {
return;
}
Matcher matcher = CONTEXT_PATH_MATCH.matcher(contextPath);
if (matcher.find()) {
throw new IllegalArgumentException("Illegal url path expression");
}
}
}

View File

@ -13,5 +13,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
version=${project.version}

View File

@ -18,47 +18,47 @@
<Configuration status="WARN">
<Appenders>
<RollingFile name="CONFIG_LOG_FILE" fileName="${sys:nacos.logging.path}/config.log"
filePattern="${sys:nacos.logging.path}/config.log.%d{yyyy-MM-dd}.%i">
filePattern="${sys:nacos.logging.path}/config.log.%d{yyyy-MM-dd}.%i">
<PatternLayout>
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %p [%-5t:%c{2}] %m%n</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="${sys:JM.LOG.FILE.SIZE:-10MB}"/>
</Policies>
<DefaultRolloverStrategy max="${sys:JM.LOG.RETAIN.COUNT:-7}"/>
</RollingFile>
<RollingFile name="NAMING_LOG_FILE" fileName="${sys:nacos.logging.path}/naming.log"
filePattern="${sys:nacos.logging.path}/naming.log.%d{yyyy-MM-dd}.%i">
filePattern="${sys:nacos.logging.path}/naming.log.%d{yyyy-MM-dd}.%i">
<PatternLayout>
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %p [%-5t:%c{2}] %m%n</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="${sys:JM.LOG.FILE.SIZE:-10MB}"/>
</Policies>
<DefaultRolloverStrategy max="${sys:JM.LOG.RETAIN.COUNT:-7}"/>
</RollingFile>
</Appenders>
<Loggers>
<Logger name="com.alibaba.nacos.client" level="${sys:com.alibaba.nacos.config.log.level:-info}"
additivity="false">
additivity="false">
<AppenderRef ref="CONFIG_LOG_FILE"/>
</Logger>
<Logger name="com.alibaba.nacos.client.config" level="${sys:com.alibaba.nacos.config.log.level:-info}"
additivity="false">
additivity="false">
<AppenderRef ref="CONFIG_LOG_FILE"/>
</Logger>
<Logger name="com.alibaba.nacos.client.naming" level="${sys:com.alibaba.nacos.naming.log.level:-info}"
additivity="false">
additivity="false">
<AppenderRef ref="NAMING_LOG_FILE"/>
</Logger>
<Root level="INFO">

View File

@ -17,54 +17,54 @@
<configuration debug="false" scan="true" scanPeriod="30 seconds" packagingData="true">
<contextName>nacos</contextName>
<appender name="CONFIG_LOG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${nacos.logging.path}/config.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>${nacos.logging.path}/config.log.%i</fileNamePattern>
<maxIndex>${JM.LOG.RETAIN.COUNT:-7}</maxIndex>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>${JM.LOG.FILE.SIZE:-10MB}</maxFileSize>
</triggeringPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %p [%-5t:%c{2}] %m%n</pattern>
</encoder>
</appender>
<appender name="NAMING_LOG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${nacos.logging.path}/naming.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>${nacos.logging.path}/naming.log.%i</fileNamePattern>
<maxIndex>${JM.LOG.RETAIN.COUNT:-7}</maxIndex>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>${JM.LOG.FILE.SIZE:-10MB}</maxFileSize>
</triggeringPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %p [%-5t:%c{2}] %m%n</pattern>
</encoder>
</appender>
<logger name="com.alibaba.nacos.client" level="${com.alibaba.nacos.config.log.level:-info}"
additivity="false">
additivity="false">
<appender-ref ref="CONFIG_LOG_FILE"/>
</logger>
<logger name="com.alibaba.nacos.client.config" level="${com.alibaba.nacos.config.log.level:-info}"
additivity="false">
additivity="false">
<appender-ref ref="CONFIG_LOG_FILE"/>
</logger>
<logger name="com.alibaba.nacos.client.naming" level="${com.alibaba.nacos.naming.log.level:-info}"
additivity="false">
additivity="false">
<appender-ref ref="NAMING_LOG_FILE"/>
</logger>

View File

@ -13,36 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Unit test for simple App.
*/
public class AppTest
extends TestCase {
/**
* Create the test case
*
* @param testName name of the test case
*/
public class AppTest extends TestCase {
public AppTest(String testName) {
super(testName);
}
/**
* @return the suite of tests being tested
*/
public static Test suite() {
return new TestSuite(AppTest.class);
}
/**
* Rigourous Test :-)
*/
public void testApp() {
assertTrue(true);
}

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