diff --git a/address/pom.xml b/address/pom.xml
new file mode 100644
index 00000000000..5621eb32134
--- /dev/null
+++ b/address/pom.xml
@@ -0,0 +1,123 @@
+
+
+
+
+ nacos-all
+ com.alibaba.nacos
+ 1.1.0
+
+
+ 4.0.0
+ nacos-address
+ jar
+
+ nacos-address ${project.version}
+ http://maven.apache.org
+
+
+ UTF-8
+ 1.8
+ 1.8
+
+
+
+
+ junit
+ junit
+ test
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+ ${project.groupId}
+ nacos-naming
+
+
+ com.alibaba.nacos
+ nacos-cmdb
+
+
+
+
+ org.mockito
+ mockito-all
+ 1.10.19
+ test
+
+
+ org.hamcrest
+ hamcrest-all
+ 1.3
+ test
+
+
+
+
+
+
+ src/main/resources
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ findbugs-maven-plugin
+ 3.0.4
+
+
+
+
+
+
+ release-address
+
+ nacos-address
+
+
+ maven-jar-plugin
+
+
+
+ true
+ true
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ com.alibaba.nacos.address.AddressServer
+
+
+
+
+ repackage
+
+
+
+
+
+
+
+
+
diff --git a/address/src/main/java/com/alibaba/nacos/address/AddressServer.java b/address/src/main/java/com/alibaba/nacos/address/AddressServer.java
new file mode 100644
index 00000000000..a963cda64f0
--- /dev/null
+++ b/address/src/main/java/com/alibaba/nacos/address/AddressServer.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.nacos.address;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * support address server.
+ *
+ * @author nacos
+ * @since 1.1.0
+ */
+@SpringBootApplication(scanBasePackages = "com.alibaba.nacos")
+public class AddressServer {
+ public static void main(String[] args) {
+
+ SpringApplication.run(AddressServer.class, args);
+ }
+}
diff --git a/address/src/main/java/com/alibaba/nacos/address/component/AddressServerGeneratorManager.java b/address/src/main/java/com/alibaba/nacos/address/component/AddressServerGeneratorManager.java
new file mode 100644
index 00000000000..0a35471eab6
--- /dev/null
+++ b/address/src/main/java/com/alibaba/nacos/address/component/AddressServerGeneratorManager.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.nacos.address.component;
+
+import com.alibaba.nacos.address.constant.AddressServerConstants;
+import com.alibaba.nacos.api.common.Constants;
+import com.alibaba.nacos.naming.core.Instance;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * will generator some result by the input parameter.
+ *
+ * @author pbting
+ * @date 2019-07-01 8:53 PM
+ * @since 1.1.0
+ */
+@Component
+public class AddressServerGeneratorManager {
+
+ 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
+ */
+ public List 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 instanceList = new ArrayList<>(ipArray.length);
+ for (String ip : ipArray) {
+ String[] ipAndPort = generateIpAndPort(ip);
+ Instance instance = new Instance();
+ instance.setIp(ipAndPort[0]);
+ instance.setPort(Integer.valueOf(ipAndPort[1]));
+ instance.setClusterName(clusterName);
+ instance.setServiceName(serviceName);
+ instance.setTenant(Constants.DEFAULT_NAMESPACE_ID);
+ instance.setApp(rawProductName);
+ instance.setEphemeral(false);
+ instanceList.add(instance);
+ }
+
+ return instanceList;
+ }
+
+ public 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, String.valueOf(AddressServerConstants.DEFAULT_SERVER_PORT)};
+ }
+
+ /**
+ * @param instanceList a instance set will generate string response to client.
+ * @return the result of response to client
+ */
+ public String generateResponseIps(List 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}
+ * @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;
+ }
+}
diff --git a/address/src/main/java/com/alibaba/nacos/address/component/AddressServerManager.java b/address/src/main/java/com/alibaba/nacos/address/component/AddressServerManager.java
new file mode 100644
index 00000000000..c3a6d01a804
--- /dev/null
+++ b/address/src/main/java/com/alibaba/nacos/address/component/AddressServerManager.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.nacos.address.component;
+
+import com.alibaba.nacos.address.constant.AddressServerConstants;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+/**
+ * This class holds the IP list of the CAI's address service.
+ *
+ * @author deshao
+ * @date 2016/4/28 20:58
+ * @since 1.1.0
+ */
+@Component
+public class AddressServerManager {
+
+ public String getRawProductName(String name) {
+
+ if (StringUtils.isBlank(name) || AddressServerConstants.DEFAULT_PRODUCT.equals(name)) {
+
+ return AddressServerConstants.DEFAULT_PRODUCT;
+ }
+
+ return name;
+ }
+
+ /**
+ *
+ * if the name is empty then return the default {@UtilAndCommons#DEFAULT_CLUSTER_NAME},
+ *
+ * or return the source name by input
+ *
+ * @param name
+ * @return
+ */
+ 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);
+ }
+
+ /**
+ * @param ips multi ip will separator by the ','
+ * @return
+ */
+ public String[] splitIps(String ips) {
+
+ if (StringUtils.isBlank(ips)) {
+
+ return new String[0];
+ }
+
+ return ips.split(AddressServerConstants.MULTI_IPS_SEPARATOR);
+ }
+}
diff --git a/address/src/main/java/com/alibaba/nacos/address/constant/AddressServerConstants.java b/address/src/main/java/com/alibaba/nacos/address/constant/AddressServerConstants.java
new file mode 100644
index 00000000000..c60881b92ec
--- /dev/null
+++ b/address/src/main/java/com/alibaba/nacos/address/constant/AddressServerConstants.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.nacos.address.constant;
+
+import com.alibaba.nacos.naming.misc.UtilsAndCommons;
+
+/**
+ * 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
+ */
+ 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
+ */
+ String MULTI_IPS_SEPARATOR = ",";
+
+ /**
+ * 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。
+ */
+ String ALIWARE_NACOS_PRODUCT_DOM_TEMPLATE = "nacos.as.%s";
+
+ /**
+ * the url for address server prefix
+ */
+ String ADDRESS_SERVER_REQUEST_URL =
+ UtilsAndCommons.NACOS_SERVER_CONTEXT + UtilsAndCommons.NACOS_SERVER_VERSION + "/as";
+
+}
diff --git a/address/src/main/java/com/alibaba/nacos/address/controller/AddressServerClusterController.java b/address/src/main/java/com/alibaba/nacos/address/controller/AddressServerClusterController.java
new file mode 100644
index 00000000000..347b792d811
--- /dev/null
+++ b/address/src/main/java/com/alibaba/nacos/address/controller/AddressServerClusterController.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.nacos.address.controller;
+
+import com.alibaba.nacos.address.component.AddressServerGeneratorManager;
+import com.alibaba.nacos.address.component.AddressServerManager;
+import com.alibaba.nacos.address.constant.AddressServerConstants;
+import com.alibaba.nacos.address.misc.Loggers;
+import com.alibaba.nacos.address.util.AddressServerParamCheckUtil;
+import com.alibaba.nacos.api.common.Constants;
+import com.alibaba.nacos.api.naming.pojo.AbstractHealthChecker;
+import com.alibaba.nacos.naming.core.Cluster;
+import com.alibaba.nacos.naming.core.Instance;
+import com.alibaba.nacos.naming.core.Service;
+import com.alibaba.nacos.naming.core.ServiceManager;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * @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;
+
+ /**
+ * @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
+ */
+ @RequestMapping(value = "", method = RequestMethod.POST)
+ public ResponseEntity postCluster(@RequestParam(required = false) String product,
+ @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);
+ ResponseEntity responseEntity;
+ try {
+ String serviceName = addressServerGeneratorManager.generateNacosServiceName(productName);
+
+ Cluster clusterObj = new Cluster();
+ clusterObj.setName(clusterName);
+ clusterObj.setHealthChecker(new AbstractHealthChecker.None());
+ serviceManager.createServiceIfAbsent(Constants.DEFAULT_NAMESPACE_ID, serviceName, false, clusterObj);
+ String[] ipArray = addressServerManager.splitIps(ips);
+ String checkResult = AddressServerParamCheckUtil.checkIps(ipArray);
+ if (AddressServerParamCheckUtil.CHECK_OK.equals(checkResult)) {
+ List 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());
+ } else {
+ responseEntity = ResponseEntity.status(HttpStatus.BAD_REQUEST).body(checkResult);
+ }
+ } catch (Exception e) {
+ responseEntity = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
+ }
+
+ return responseEntity;
+ }
+
+ /**
+ * @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
+ */
+ @RequestMapping(value = "", method = RequestMethod.DELETE)
+ public ResponseEntity deleteCluster(@RequestParam(required = false) String product,
+ @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.");
+ 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.");
+ } else {
+
+ if (StringUtils.isBlank(ips)) {
+ // delete all ips from the cluster
+ responseEntity = ResponseEntity.status(HttpStatus.BAD_REQUEST).body("ips must not be empty.");
+ } else {
+ // delete specified ip list
+ String[] ipArray = addressServerManager.splitIps(ips);
+ String checkResult = AddressServerParamCheckUtil.checkIps(ipArray);
+ if (AddressServerParamCheckUtil.CHECK_OK.equals(checkResult)) {
+ List 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;
+ }
+
+}
diff --git a/address/src/main/java/com/alibaba/nacos/address/controller/ServerListController.java b/address/src/main/java/com/alibaba/nacos/address/controller/ServerListController.java
new file mode 100644
index 00000000000..263fc897aca
--- /dev/null
+++ b/address/src/main/java/com/alibaba/nacos/address/controller/ServerListController.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.nacos.address.controller;
+
+import com.alibaba.nacos.address.component.AddressServerGeneratorManager;
+import com.alibaba.nacos.api.common.Constants;
+import com.alibaba.nacos.naming.core.Cluster;
+import com.alibaba.nacos.naming.core.Service;
+import com.alibaba.nacos.naming.core.ServiceManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @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;
+
+ /**
+ * @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
+ */
+ @RequestMapping(value = "/{product}/{cluster}", method = RequestMethod.GET)
+ 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.");
+ }
+
+ Cluster clusterObj = service.getClusterMap().get(cluster);
+ return ResponseEntity.status(HttpStatus.OK).body(addressServerBuilderManager.generateResponseIps(clusterObj.allIPs(false)));
+ }
+}
diff --git a/address/src/main/java/com/alibaba/nacos/address/misc/Loggers.java b/address/src/main/java/com/alibaba/nacos/address/misc/Loggers.java
new file mode 100644
index 00000000000..dd707de100b
--- /dev/null
+++ b/address/src/main/java/com/alibaba/nacos/address/misc/Loggers.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.nacos.address.misc;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author pbting
+ * @date 2019-07-04 4:34 PM
+ */
+public class Loggers {
+
+ public static final Logger addressLogger = LoggerFactory.getLogger("com.alibaba.nacos.address.main");
+}
diff --git a/address/src/main/java/com/alibaba/nacos/address/util/AddressServerParamCheckUtil.java b/address/src/main/java/com/alibaba/nacos/address/util/AddressServerParamCheckUtil.java
new file mode 100644
index 00000000000..ec4e991d31b
--- /dev/null
+++ b/address/src/main/java/com/alibaba/nacos/address/util/AddressServerParamCheckUtil.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.nacos.address.util;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 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);
+
+ public static String checkIps(String... ips) {
+
+ if (ips == null || ips.length == 0) {
+
+ return CHECK_OK;
+ }
+ // illegal response
+ StringBuilder illegalResponse = new StringBuilder();
+ for (String ip : ips) {
+ Matcher matcher = IP_PATTERN.matcher(ip);
+ if (matcher.matches()) {
+ continue;
+ }
+ illegalResponse.append(ip + ",");
+ }
+
+ if (illegalResponse.length() == 0) {
+ return CHECK_OK;
+ }
+
+ return ILLEGAL_IP_PREFIX + illegalResponse.substring(0, illegalResponse.length() - 1);
+ }
+}
diff --git a/address/src/main/resources/META-INF/logback/nacos-included.xml b/address/src/main/resources/META-INF/logback/nacos-included.xml
new file mode 100644
index 00000000000..44f88e2c072
--- /dev/null
+++ b/address/src/main/resources/META-INF/logback/nacos-included.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+ ${LOG_HOME}/nacos-address.log
+ true
+
+ ${LOG_HOME}/nacos-address.log.%d{yyyy-MM-dd}.%i
+ 2GB
+ 15
+ 7GB
+ true
+
+
+ %date %level %msg%n%n
+ UTF-8
+
+
+
+
+
+
+
+
+
diff --git a/address/src/main/resources/META-INF/nacos-default.properties b/address/src/main/resources/META-INF/nacos-default.properties
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/address/src/main/resources/application.properties b/address/src/main/resources/application.properties
new file mode 100644
index 00000000000..8a6c9ff9b65
--- /dev/null
+++ b/address/src/main/resources/application.properties
@@ -0,0 +1,2 @@
+server.port=8080
+server.servlet.context-path=/
diff --git a/address/src/test/java/com/alibaba/nacos/address/AddressServerControllerTests.java b/address/src/test/java/com/alibaba/nacos/address/AddressServerControllerTests.java
new file mode 100644
index 00000000000..b549536aab9
--- /dev/null
+++ b/address/src/test/java/com/alibaba/nacos/address/AddressServerControllerTests.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.nacos.address;
+
+import org.junit.Test;
+
+import java.util.HashMap;
+
+/**
+ * @author pbting
+ * @date 2019-06-18 2:37 PM
+ */
+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 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 deleteIp = new HashMap<>();
+ deleteIp.put("ips", "127.0.0.104");
+ String response = SimpleHttpTestUtils.doDelete("http://127.0.0.1:8080/nacos/v1/as/nodes", deleteIp, "UTF-8");
+ System.err.println(response);
+ }
+
+ @Test
+ public void deleteClusterWithSpecIp() {
+ HashMap params = new HashMap<>();
+ params.put("ips", "127.0.0.103");
+ String response = SimpleHttpTestUtils.doDelete("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
+ System.err.println(response);
+ }
+
+ @Test
+ public void putCluster() {
+
+ String ips = "127.0.0.114";
+ HashMap 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 params = new HashMap<>();
+ params.put("ips", ips);
+ params.put("product", PRODUCT_CONFIG);
+ String response = SimpleHttpTestUtils.doPost("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
+ System.err.println(response);
+ }
+
+ @Test
+ public void getClusterWithProduct() {
+ HashMap params = new HashMap<>();
+ String getUrl = String.format(GET_SERVERLIST_URL_FORMART, PRODUCT_CONFIG, DEFAULT_URL_CLUSTER);
+ String response = SimpleHttpTestUtils.doGet(getUrl, params, "UTF-8");
+ System.err.println(response);
+ }
+
+ @Test
+ public void deleteClusterWithProduct() {
+ HashMap params = new HashMap<>();
+ params.put("product", PRODUCT_CONFIG);
+ String response = SimpleHttpTestUtils.doDelete("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
+ System.err.println(response);
+ }
+
+ @Test
+ public void deleteClusterWithProductAndIp() {
+ HashMap params = new HashMap<>();
+ params.put("product", PRODUCT_CONFIG);
+ params.put("ips", "127.0.0.196");
+ String response = SimpleHttpTestUtils.doDelete("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
+ System.err.println(response);
+ }
+
+ @Test
+ public void putClusterWithProduct() {
+
+ String ips = "127.0.0.196";
+ HashMap params = new HashMap<>();
+ params.put("ips", ips);
+ params.put("product", PRODUCT_CONFIG);
+ String response = SimpleHttpTestUtils.doPut("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
+ System.err.println(response);
+ }
+
+
+ //-----------------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 params = new HashMap<>();
+ params.put("ips", ips);
+ params.put("product", PRODUCT_NAMING);
+ params.put("cluster", "cluster01");
+ String response = SimpleHttpTestUtils.doPost("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
+ System.err.println(response);
+ }
+
+ @Test
+ public void getClusterWithProductAndCluster() {
+ HashMap params = new HashMap<>();
+ String getUrl = String.format(GET_SERVERLIST_URL_FORMART, PRODUCT_NAMING, "cluster01");
+ String response = SimpleHttpTestUtils.doGet(getUrl, params, "UTF-8");
+ System.err.println(response);
+ }
+
+ @Test
+ public void deleteClusterWithProductAndCluster() {
+ HashMap params = new HashMap<>();
+ params.put("product", PRODUCT_NAMING);
+ params.put("cluster", "cluster01");
+ String response = SimpleHttpTestUtils.doDelete("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
+ System.err.println(response);
+ }
+
+ @Test
+ public void deleteClusterWithProductAndClusterAndIp() {
+ HashMap params = new HashMap<>();
+ params.put("product", PRODUCT_NAMING);
+ params.put("cluster", "cluster01");
+ params.put("ips", "127.0.0.200");
+ String response = SimpleHttpTestUtils.doDelete("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
+ System.err.println(response);
+ }
+
+ @Test
+ public void putClusterWithProductAndCluster() {
+
+ String ips = "127.0.0.171";
+ HashMap params = new HashMap<>();
+ params.put("ips", ips);
+ params.put("product", PRODUCT_NAMING);
+ params.put("cluster", "cluster01");
+ String response = SimpleHttpTestUtils.doPut("http://127.0.0.1:8080/nacos/v1/as/nodes", params, "UTF-8");
+ System.err.println(response);
+ }
+}
diff --git a/address/src/test/java/com/alibaba/nacos/address/ParamCheckUtilTests.java b/address/src/test/java/com/alibaba/nacos/address/ParamCheckUtilTests.java
new file mode 100644
index 00000000000..395bfcac429
--- /dev/null
+++ b/address/src/test/java/com/alibaba/nacos/address/ParamCheckUtilTests.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.nacos.address;
+
+import com.alibaba.nacos.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));
+ }
+}
diff --git a/address/src/test/java/com/alibaba/nacos/address/SimpleHttpTestUtils.java b/address/src/test/java/com/alibaba/nacos/address/SimpleHttpTestUtils.java
new file mode 100644
index 00000000000..d604c965901
--- /dev/null
+++ b/address/src/test/java/com/alibaba/nacos/address/SimpleHttpTestUtils.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.nacos.address;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.util.Map;
+
+/**
+ * @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 int READ_TIME_OUT = 2000;
+
+ /**
+ * 请求编码
+ */
+ public static String REQUEST_ENCODING = "UTF-8";
+
+ /**
+ * 接收编码
+ */
+ public static String RESPONSE_ENCODING = "UTF-8";
+
+ public static final short OK = 200;
+
+ public static final short Bad_Request = 400;
+
+ public static final short Internal_Server_Error = 500;
+
+ public static final short PARAM_ERROR_NO_ANALYSESOR = 1000;
+
+ /**
+ *