Merge branch 'develop' into service-test
diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar
new file mode 100755
index 0000000..01e6799
--- /dev/null
+++ b/.mvn/wrapper/maven-wrapper.jar
Binary files differ
diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties
new file mode 100755
index 0000000..b6e6781
--- /dev/null
+++ b/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index 259bf59..414bb88 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,8 +4,15 @@
jdk:
- oraclejdk8
- oraclejdk11
+
+cache:
+ directories:
+ - $HOME/.m2
+
+install: true
+
script:
- - travis_wait 30 mvn clean package
+ - travis_wait 30 ./mvnw clean install -DskipTests=false -Dcheckstyle.skip=false -Dmaven.javadoc.skip=true
after_success:
- bash <(curl -s https://codecov.io/bash)
diff --git a/README_ZH.md b/README_ZH.md
index 625acfc..0790ee0 100644
--- a/README_ZH.md
+++ b/README_ZH.md
@@ -24,7 +24,6 @@
* 标准spring boot工程
* **注意** 本分支依赖Dubbo2.7-SNAPSHOT版本,该Dubbo版本还未正式发布,因此如果发现依赖方面的错误,请清空本地库中的dubbo2.7相关文件
* [application.properties配置说明](https://github.com/apache/incubator-dubbo-ops/wiki/Dubbo-Admin%E9%85%8D%E7%BD%AE%E8%AF%B4%E6%98%8E)
-* **注意** 本分支依赖Dubbo2.7-SNAPSHOT版本,该Dubbo版本还未正式发布,因此如果发现依赖方面的错误,请清空本地库中的dubbo2.7相关文件
* 在项目根目录(incubator-dubbo-ops)第一次构建需要强制更新: `mvn -Dmaven.test.skip=true clean -U package`
diff --git a/codestyle/checkstyle.xml b/codestyle/checkstyle.xml
new file mode 100644
index 0000000..9c7581b
--- /dev/null
+++ b/codestyle/checkstyle.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!DOCTYPE module PUBLIC
+ "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
+ "http://checkstyle.sourceforge.net/dtds/configuration_1_3.dtd">
+
+<module name="Checker">
+ <property name="charset" value="UTF-8"/>
+ <property name="fileExtensions" value="java"/>
+
+ <!-- TreeWalker Checks -->
+ <module name="TreeWalker">
+ <module name="SuppressWarningsHolder" />
+
+ <module name="AvoidStarImport"/>
+ <module name="AvoidEscapedUnicodeCharacters">
+ <property name="allowEscapesForControlCharacters" value="true"/>
+ <property name="allowByTailComment" value="true"/>
+ <property name="allowNonPrintableEscapes" value="true"/>
+ </module>
+ <module name="NoLineWrap"/>
+ <module name="OuterTypeFilename"/>
+ <module name="UnusedImports"/>
+
+ </module>
+</module>
diff --git a/codestyle/dubbo_codestyle_for_idea.xml b/codestyle/dubbo_codestyle_for_idea.xml
new file mode 100644
index 0000000..1cbbe37
--- /dev/null
+++ b/codestyle/dubbo_codestyle_for_idea.xml
@@ -0,0 +1,33 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You under the Apache License, Version 2.0
+ ~ (the "License"); you may not use this file except in compliance with
+ ~ the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<code_scheme name="dubbo_codestyle">
+ <option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99"/>
+ <option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99"/>
+ <option name="IMPORT_LAYOUT_TABLE">
+ <value>
+ <package name="org.apache.dubbo.admin" withSubpackages="true" static="false"/>
+ <emptyLine/>
+ <package name="" withSubpackages="true" static="false"/>
+ <emptyLine/>
+ <package name="javax" withSubpackages="true" static="false"/>
+ <package name="java" withSubpackages="true" static="false"/>
+ <emptyLine/>
+ <package name="" withSubpackages="true" static="true"/>
+ </value>
+ </option>
+</code_scheme>
diff --git a/dubbo-admin-backend/pom.xml b/dubbo-admin-backend/pom.xml
index dd10133..c958c30 100644
--- a/dubbo-admin-backend/pom.xml
+++ b/dubbo-admin-backend/pom.xml
@@ -32,6 +32,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
+ <mockito-version>2.23.4</mockito-version>
</properties>
<dependencies>
@@ -123,6 +124,12 @@
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</dependency>
+
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <version>${mockito-version}</version>
+ </dependency>
</dependencies>
<build>
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/Constants.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/Constants.java
index ef2ef89..6bd38ca 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/Constants.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/Constants.java
@@ -54,6 +54,7 @@
public static final String CONSUMERS_CATEGORY = "consumers";
public static final String SPECIFICATION_VERSION_KEY = "release";
public static final String GLOBAL_CONFIG = "global";
+ public static final String GLOBAL_CONFIG_PATH = "config/dubbo/dubbo.properties";
public static final Set<String> CONFIGS = new HashSet<>();
static {
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/OverrideUtils.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/OverrideUtils.java
index cdad836..fb18d56 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/OverrideUtils.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/OverrideUtils.java
@@ -16,8 +16,9 @@
*/
package org.apache.dubbo.admin.common.util;
-import org.apache.dubbo.admin.model.domain.*;
+import org.apache.dubbo.admin.model.domain.LoadBalance;
import org.apache.dubbo.admin.model.domain.Override;
+import org.apache.dubbo.admin.model.domain.Weight;
import org.apache.dubbo.admin.model.dto.BalancingDTO;
import org.apache.dubbo.admin.model.dto.DynamicConfigDTO;
import org.apache.dubbo.admin.model.dto.WeightDTO;
@@ -25,7 +26,11 @@
import org.apache.dubbo.admin.model.store.OverrideDTO;
import org.apache.dubbo.common.utils.StringUtils;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
/**
* OverrideUtils.java
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/ParseUtils.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/ParseUtils.java
index 13035db..5a2b55d 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/ParseUtils.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/ParseUtils.java
@@ -18,7 +18,13 @@
import org.apache.dubbo.common.utils.StringUtils;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+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.ConcurrentMap;
import java.util.regex.Matcher;
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/RouteUtils.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/RouteUtils.java
index cb2c759..81b505c 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/RouteUtils.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/common/util/RouteUtils.java
@@ -20,14 +20,20 @@
import org.apache.dubbo.admin.model.dto.AccessDTO;
import org.apache.dubbo.admin.model.dto.ConditionRouteDTO;
import org.apache.dubbo.admin.model.dto.TagRouteDTO;
-import org.apache.dubbo.admin.model.store.BlackWhiteList;
import org.apache.dubbo.admin.model.store.RoutingRule;
import org.apache.dubbo.admin.model.store.TagRoute;
import org.apache.dubbo.common.utils.StringUtils;
import java.text.ParseException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
import java.util.Map.Entry;
+import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java
index 382e2b2..55be526 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java
@@ -23,14 +23,12 @@
import org.apache.dubbo.admin.registry.config.GovernanceConfiguration;
import org.apache.dubbo.admin.registry.metadata.MetaDataCollector;
import org.apache.dubbo.admin.registry.metadata.impl.NoOpMetadataCollector;
-import org.apache.dubbo.admin.service.ManagementService;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.registry.Registry;
import org.apache.dubbo.registry.RegistryFactory;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/AccessesController.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/AccessesController.java
index ac350c5..055b48c 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/AccessesController.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/AccessesController.java
@@ -16,23 +16,31 @@
*/
package org.apache.dubbo.admin.controller;
-import org.apache.dubbo.admin.common.exception.VersionValidationException;
-import org.apache.dubbo.admin.common.util.Constants;
-import org.apache.dubbo.admin.model.dto.ConditionRouteDTO;
-import org.apache.dubbo.admin.service.ProviderService;
-import org.apache.dubbo.common.logger.Logger;
-import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.admin.common.exception.ParamValidationException;
import org.apache.dubbo.admin.common.exception.ResourceNotFoundException;
+import org.apache.dubbo.admin.common.exception.VersionValidationException;
+import org.apache.dubbo.admin.common.util.Constants;
import org.apache.dubbo.admin.model.dto.AccessDTO;
+import org.apache.dubbo.admin.model.dto.ConditionRouteDTO;
+import org.apache.dubbo.admin.service.ProviderService;
import org.apache.dubbo.admin.service.RouteService;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+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.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
import java.text.ParseException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
@RestController
@RequestMapping("/api/{env}/rules/access")
@@ -89,7 +97,7 @@
throw new ParamValidationException("Either Service or application is required.");
}
String application = accessDTO.getApplication();
- if (StringUtils.isNotEmpty(application) && this.providerService.findVersionInApplication(application).equals("2.6")) {
+ if (StringUtils.isNotEmpty(application) && "2.6".equals(providerService.findVersionInApplication(application))) {
throw new VersionValidationException("dubbo 2.6 does not support application scope blackwhite list config");
}
if (accessDTO.getBlacklist() == null && accessDTO.getWhitelist() == null) {
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ConditionRoutesController.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ConditionRoutesController.java
index f764801..cd1b894 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ConditionRoutesController.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ConditionRoutesController.java
@@ -27,7 +27,13 @@
import org.apache.dubbo.admin.service.RouteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+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.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/LoadBalanceController.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/LoadBalanceController.java
index a803527..b314aed 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/LoadBalanceController.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/LoadBalanceController.java
@@ -27,7 +27,13 @@
import org.apache.dubbo.admin.service.ProviderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+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.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ManagementController.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ManagementController.java
index c846ce6..b12c689 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ManagementController.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ManagementController.java
@@ -25,7 +25,12 @@
import org.apache.dubbo.admin.service.ProviderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.HashSet;
@@ -72,7 +77,7 @@
List<ConfigDTO> configDTOs = new ArrayList<>();
if (key.equals(Constants.ANY_VALUE)) {
query = providerService.findApplications();
- query.add("global");
+ query.add(Constants.GLOBAL_CONFIG);
} else {
query.add(key);
}
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/OverridesController.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/OverridesController.java
index fb19178..82ba032 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/OverridesController.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/OverridesController.java
@@ -27,7 +27,13 @@
import org.apache.dubbo.admin.service.ProviderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+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.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java
index dfbc607..ae9069f 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java
@@ -17,8 +17,8 @@
package org.apache.dubbo.admin.controller;
-import com.ctrip.framework.apollo.core.enums.Env;
import com.google.gson.Gson;
+import org.apache.dubbo.admin.common.util.Constants;
import org.apache.dubbo.admin.common.util.ConvertUtil;
import org.apache.dubbo.admin.model.domain.Consumer;
import org.apache.dubbo.admin.model.domain.Provider;
@@ -26,16 +26,18 @@
import org.apache.dubbo.admin.model.dto.ServiceDetailDTO;
import org.apache.dubbo.admin.service.ConsumerService;
import org.apache.dubbo.admin.service.ProviderService;
-import org.apache.dubbo.admin.common.util.Constants;
import org.apache.dubbo.metadata.definition.model.FullServiceDefinition;
import org.apache.dubbo.metadata.identifier.MetadataIdentifier;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.*;
+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.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
-import java.util.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
@RestController
@RequestMapping("/api/{env}")
@@ -43,11 +45,13 @@
private final ProviderService providerService;
private final ConsumerService consumerService;
+ private final Gson gson;
@Autowired
public ServiceController(ProviderService providerService, ConsumerService consumerService) {
this.providerService = providerService;
this.consumerService = consumerService;
+ this.gson = new Gson();
}
@RequestMapping( value = "/service", method = RequestMethod.GET)
@@ -56,8 +60,6 @@
return providerService.getServiceDTOS(pattern, filter, env);
}
-
-
@RequestMapping(value = "/service/{service}", method = RequestMethod.GET)
public ServiceDetailDTO serviceDetail(@PathVariable String service, @PathVariable String env) {
service = service.replace(Constants.ANY_VALUE, Constants.PATH_SEPARATOR);
@@ -78,7 +80,6 @@
serviceDetailDTO.setConsumers(consumers);
serviceDetailDTO.setProviders(providers);
if (metadata != null) {
- Gson gson = new Gson();
FullServiceDefinition serviceDefinition = gson.fromJson(metadata, FullServiceDefinition.class);
serviceDetailDTO.setMetadata(serviceDefinition);
}
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/TagRoutesController.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/TagRoutesController.java
index e097d48..521c9d2 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/TagRoutesController.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/TagRoutesController.java
@@ -27,7 +27,13 @@
import org.apache.dubbo.admin.service.RouteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+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.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/WeightController.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/WeightController.java
index 2146a01..3333e90 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/WeightController.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/controller/WeightController.java
@@ -22,17 +22,18 @@
import org.apache.dubbo.admin.common.exception.ResourceNotFoundException;
import org.apache.dubbo.admin.common.exception.VersionValidationException;
import org.apache.dubbo.admin.common.util.Constants;
-import org.apache.dubbo.admin.common.util.ConvertUtil;
-import org.apache.dubbo.admin.model.dto.AccessDTO;
import org.apache.dubbo.admin.model.dto.WeightDTO;
import org.apache.dubbo.admin.service.OverrideService;
-import org.apache.dubbo.admin.model.domain.Override;
-import org.apache.dubbo.admin.model.domain.Weight;
-import org.apache.dubbo.admin.common.util.OverrideUtils;
import org.apache.dubbo.admin.service.ProviderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+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.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/AccessDTO.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/AccessDTO.java
index 8b8e7b4..e66f3ba 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/AccessDTO.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/AccessDTO.java
@@ -16,7 +16,6 @@
*/
package org.apache.dubbo.admin.model.dto;
-import java.util.List;
import java.util.Set;
public class AccessDTO extends BaseDTO {
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDTO.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDTO.java
index 3822291..0202526 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDTO.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDTO.java
@@ -17,9 +17,10 @@
package org.apache.dubbo.admin.model.dto;
-import java.util.Objects;
import org.apache.commons.lang3.StringUtils;
+import java.util.Objects;
+
public class ServiceDTO implements Comparable<ServiceDTO>{
private String service;
private String appName;
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/registry/config/impl/ZookeeperConfiguration.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/registry/config/impl/ZookeeperConfiguration.java
index 1eed438..362dd26 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/registry/config/impl/ZookeeperConfiguration.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/registry/config/impl/ZookeeperConfiguration.java
@@ -17,17 +17,16 @@
package org.apache.dubbo.admin.registry.config.impl;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.dubbo.admin.common.util.Constants;
import org.apache.dubbo.admin.registry.config.GovernanceConfiguration;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.curator.framework.CuratorFramework;
-import org.apache.curator.framework.CuratorFrameworkFactory;
-import org.apache.curator.retry.ExponentialBackoffRetry;
-
public class ZookeeperConfiguration implements GovernanceConfiguration {
private static final Logger logger = LoggerFactory.getLogger(ZookeeperConfiguration.class);
private CuratorFramework zkClient;
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/RegistryServerSync.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/RegistryServerSync.java
index 1cd7bb5..6b28f02 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/RegistryServerSync.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/RegistryServerSync.java
@@ -31,7 +31,11 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
-import java.util.*;
+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.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/ManagementServiceImpl.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/ManagementServiceImpl.java
index d43e6de..a1668fd 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/ManagementServiceImpl.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/ManagementServiceImpl.java
@@ -22,16 +22,14 @@
import org.apache.dubbo.admin.service.ManagementService;
import org.springframework.stereotype.Component;
+import static org.apache.dubbo.admin.common.util.Constants.GLOBAL_CONFIG_PATH;
+
@Component
public class ManagementServiceImpl extends AbstractService implements ManagementService {
-
-
- private static String globalConfigPath = "config/dubbo/dubbo.properties";
-
@Override
public void setConfig(ConfigDTO config) {
if (Constants.GLOBAL_CONFIG.equals(config.getKey())) {
- dynamicConfiguration.setConfig(globalConfigPath, config.getConfig());
+ dynamicConfiguration.setConfig(GLOBAL_CONFIG_PATH, config.getConfig());
} else {
dynamicConfiguration.setConfig(getPath(config.getKey()), config.getConfig());
}
@@ -40,7 +38,7 @@
@Override
public String getConfig(String key) {
if (Constants.GLOBAL_CONFIG.equals(key)) {
- return dynamicConfiguration.getConfig(globalConfigPath);
+ return dynamicConfiguration.getConfig(GLOBAL_CONFIG_PATH);
}
return dynamicConfiguration.getConfig(getPath(key));
}
@@ -48,7 +46,7 @@
@Override
public String getConfigPath(String key) {
if (Constants.GLOBAL_CONFIG.equals(key)) {
- return dynamicConfiguration.getPath(globalConfigPath);
+ return dynamicConfiguration.getPath(GLOBAL_CONFIG_PATH);
}
return dynamicConfiguration.getPath(getPath(key));
}
@@ -57,7 +55,7 @@
public boolean updateConfig(ConfigDTO configDTO) {
String key = configDTO.getKey();
if (Constants.GLOBAL_CONFIG.equals(key)) {
- dynamicConfiguration.setConfig(globalConfigPath, configDTO.getConfig());
+ dynamicConfiguration.setConfig(GLOBAL_CONFIG_PATH, configDTO.getConfig());
} else {
dynamicConfiguration.setConfig(getPath(key), configDTO.getConfig());
}
@@ -67,7 +65,7 @@
@Override
public boolean deleteConfig(String key) {
if (Constants.GLOBAL_CONFIG.equals(key)) {
- dynamicConfiguration.deleteConfig(globalConfigPath);
+ dynamicConfiguration.deleteConfig(GLOBAL_CONFIG_PATH);
} else {
dynamicConfiguration.deleteConfig(getPath(key));
}
diff --git a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java
index 98e3e63..10a4fe4 100644
--- a/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java
+++ b/dubbo-admin-backend/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java
@@ -17,6 +17,7 @@
package org.apache.dubbo.admin.service.impl;
import org.apache.dubbo.admin.common.exception.ParamValidationException;
+import org.apache.dubbo.admin.common.util.Constants;
import org.apache.dubbo.admin.common.util.Pair;
import org.apache.dubbo.admin.common.util.ParseUtils;
import org.apache.dubbo.admin.common.util.SyncUtils;
@@ -24,15 +25,21 @@
import org.apache.dubbo.admin.model.dto.ServiceDTO;
import org.apache.dubbo.admin.service.OverrideService;
import org.apache.dubbo.admin.service.ProviderService;
-import org.apache.dubbo.admin.common.util.Constants;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.metadata.identifier.MetadataIdentifier;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeSet;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
diff --git a/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/AbstractSpringIntegrationTest.java b/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/AbstractSpringIntegrationTest.java
index a151d3b..5640c30 100644
--- a/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/AbstractSpringIntegrationTest.java
+++ b/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/AbstractSpringIntegrationTest.java
@@ -17,7 +17,6 @@
package org.apache.dubbo.admin;
-import java.io.IOException;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.RetryOneTime;
@@ -29,11 +28,13 @@
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.test.context.ActiveProfiles;
-import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.client.RestTemplate;
+import java.io.IOException;
+
@ActiveProfiles("test")
-@RunWith(SpringRunner.class)
+@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public abstract class AbstractSpringIntegrationTest {
protected RestTemplate restTemplate = (new TestRestTemplate()).getRestTemplate();
diff --git a/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/common/util/CoderUtilTest.java b/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/common/util/CoderUtilTest.java
new file mode 100644
index 0000000..7c9daf5
--- /dev/null
+++ b/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/common/util/CoderUtilTest.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.common.util;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Java6Assertions.fail;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+public class CoderUtilTest {
+
+ @Test
+ public void MD5_16bit() {
+ assertNull(CoderUtil.MD5_16bit(null));
+
+ String input = "dubbo";
+ String output = "2CC9DEED96FE012E";
+ assertEquals(output, CoderUtil.MD5_16bit(input));
+ }
+
+ @Test
+ public void MD5_32bit() {
+ String input = null;
+ assertNull(CoderUtil.MD5_32bit(input));
+
+ input = "dubbo";
+ String output = "AA4E1B8C2CC9DEED96FE012EF2E0752A";
+ assertEquals(output, CoderUtil.MD5_32bit(input));
+ }
+
+ @Test
+ public void MD5_32bit1() {
+ byte[] input = null;
+ assertNull(CoderUtil.MD5_32bit(input));
+
+ input = "dubbo".getBytes();
+ String output = "AA4E1B8C2CC9DEED96FE012EF2E0752A";
+ assertEquals(output, CoderUtil.MD5_32bit(input));
+ }
+
+ @Test
+ public void decodeBase64() {
+ try {
+ CoderUtil.decodeBase64(null);
+ fail("when param is null, this should throw exception");
+ } catch (Exception e) {
+ }
+
+ String input = "ZHViYm8=";
+ String output = "dubbo";
+ assertEquals(output, CoderUtil.decodeBase64(input));
+ }
+}
\ No newline at end of file
diff --git a/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/config/ConfigCenterTest.java b/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/config/ConfigCenterTest.java
index 1be2ba9..cb81fa7 100644
--- a/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/config/ConfigCenterTest.java
+++ b/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/config/ConfigCenterTest.java
@@ -1,3 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package org.apache.dubbo.admin.config;
import org.apache.curator.framework.CuratorFramework;
diff --git a/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/controller/AccessesControllerTest.java b/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/controller/AccessesControllerTest.java
new file mode 100644
index 0000000..fc494ba
--- /dev/null
+++ b/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/controller/AccessesControllerTest.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.controller;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.dubbo.admin.AbstractSpringIntegrationTest;
+import org.apache.dubbo.admin.model.dto.AccessDTO;
+import org.apache.dubbo.admin.model.dto.ConditionRouteDTO;
+import org.apache.dubbo.admin.service.ProviderService;
+import org.apache.dubbo.admin.service.RouteService;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.ResponseEntity;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class AccessesControllerTest extends AbstractSpringIntegrationTest {
+
+ private final String env = "whatever";
+
+ @MockBean
+ private RouteService routeService;
+ @MockBean
+ private ProviderService providerService;
+ @Autowired
+ private ObjectMapper objectMapper;
+
+ @Test
+ public void searchAccess() throws IOException {
+ AccessDTO accessDTO = new AccessDTO();
+ ResponseEntity<String> response;
+ String exceptResponseBody;
+ // application and service is all empty
+ response = restTemplate.getForEntity(url("/api/{env}/rules/access"), String.class, env);
+ Map map = objectMapper.readValue(response.getBody(), Map.class);
+ assertFalse("should return a fail response", (Boolean) map.get("success"));
+
+ // when application is present
+ String application = "applicationName";
+ when(routeService.findAccess(application)).thenReturn(accessDTO);
+ response = restTemplate.getForEntity(url("/api/{env}/rules/access?application={application}"), String.class, env, application);
+ exceptResponseBody = objectMapper.writeValueAsString(Collections.singletonList(accessDTO));
+ assertEquals(exceptResponseBody, response.getBody());
+
+ // when service is present
+ String service = "serviceName";
+ when(routeService.findAccess(service)).thenReturn(accessDTO);
+ response = restTemplate.getForEntity(url("/api/{env}/rules/access?service={service}"), String.class, env, service);
+ exceptResponseBody = objectMapper.writeValueAsString(Collections.singletonList(accessDTO));
+ assertEquals(exceptResponseBody, response.getBody());
+ }
+
+ @Test
+ public void detailAccess() throws JsonProcessingException {
+ String id = "1";
+ AccessDTO accessDTO = new AccessDTO();
+ when(routeService.findAccess(id)).thenReturn(accessDTO);
+ ResponseEntity<String> response = restTemplate.getForEntity(url("/api/{env}/rules/access/{id}"), String.class, env, id);
+ String exceptResponseBody = objectMapper.writeValueAsString(accessDTO);
+ assertEquals(exceptResponseBody, response.getBody());
+ }
+
+ @Test
+ public void deleteAccess() {
+ String id = "1";
+ restTemplate.delete(url("/api/{env}/rules/access/{id}"), env, id);
+ verify(routeService).deleteAccess(id);
+ }
+
+ @Test
+ public void createAccess() {
+ AccessDTO accessDTO = new AccessDTO();
+ String application = "applicationName";
+
+ restTemplate.postForLocation(url("/api/{env}/rules/access"), accessDTO, env);
+ // when application is present & dubbo's version is 2.6
+ accessDTO.setApplication(application);
+ when(providerService.findVersionInApplication(application)).thenReturn("2.6");
+ restTemplate.postForLocation(url("/api/{env}/rules/access"), accessDTO, env);
+ // dubbo's version is 2.7
+ when(providerService.findVersionInApplication(application)).thenReturn("2.7");
+ restTemplate.postForLocation(url("/api/{env}/rules/access"), accessDTO, env);
+ // black white list is not null
+ accessDTO.setBlacklist(new HashSet<>());
+ accessDTO.setWhitelist(new HashSet<>());
+ restTemplate.postForLocation(url("/api/{env}/rules/access"), accessDTO, env);
+ verify(routeService).createAccess(any(AccessDTO.class));
+ }
+
+ @Test
+ public void updateAccess() throws IOException {
+ AccessDTO accessDTO = new AccessDTO();
+ String id = "1";
+ // when id is 'Unknown ID'
+ restTemplate.put(url("/api/{env}/rules/access/{id}"), accessDTO, env, id);
+ verify(routeService).findConditionRoute(id);
+ //
+ ConditionRouteDTO conditionRouteDTO = mock(ConditionRouteDTO.class);
+ when(routeService.findConditionRoute(id)).thenReturn(conditionRouteDTO);
+ restTemplate.put(url("/api/{env}/rules/access/{id}"), accessDTO, env, id);
+ verify(routeService).updateAccess(any(AccessDTO.class));
+ }
+}
\ No newline at end of file
diff --git a/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/controller/ConditionRoutesControllerTest.java b/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/controller/ConditionRoutesControllerTest.java
new file mode 100644
index 0000000..27f2962
--- /dev/null
+++ b/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/controller/ConditionRoutesControllerTest.java
@@ -0,0 +1,291 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.controller;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Collectors;
+import org.apache.dubbo.admin.AbstractSpringIntegrationTest;
+import org.apache.dubbo.admin.common.util.YamlParser;
+import org.apache.dubbo.admin.model.dto.ConditionRouteDTO;
+import org.apache.dubbo.admin.model.store.RoutingRule;
+import org.apache.dubbo.admin.service.ProviderService;
+import org.junit.After;
+import org.junit.Test;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+public class ConditionRoutesControllerTest extends AbstractSpringIntegrationTest {
+ private final String env = "whatever";
+
+ @MockBean
+ private ProviderService providerService;
+
+ @After
+ public void tearDown() throws Exception {
+ if (zkClient.checkExists().forPath("/dubbo") != null) {
+ zkClient.delete().deletingChildrenIfNeeded().forPath("/dubbo");
+ }
+ }
+
+ @Test
+ public void shouldThrowWhenParamInvalid() {
+ String uuid = UUID.randomUUID().toString();
+
+ ConditionRouteDTO dto = new ConditionRouteDTO();
+ ResponseEntity<String> responseEntity = restTemplate.postForEntity(
+ url("/api/{env}/rules/route/condition"), dto, String.class, env
+ );
+ assertThat(responseEntity.getStatusCode(), is(HttpStatus.BAD_REQUEST));
+ assertThat(responseEntity.getBody(), containsString("serviceName and app is Empty!"));
+
+ dto.setApplication("application" + uuid);
+ when(providerService.findVersionInApplication(dto.getApplication())).thenReturn("2.6");
+ responseEntity = restTemplate.postForEntity(
+ url("/api/{env}/rules/route/condition"), dto, String.class, env
+ );
+ assertThat(responseEntity.getStatusCode(), is(HttpStatus.INTERNAL_SERVER_ERROR));
+ assertThat(responseEntity.getBody(), containsString("dubbo 2.6 does not support application scope routing rule"));
+ }
+
+ @Test
+ public void shouldCreateRule() {
+ String uuid = UUID.randomUUID().toString();
+ String application = "application" + uuid;
+ String service = "service" + uuid;
+ List<String> conditions = Collections.singletonList("=> host != 172.22.3.91");
+
+ ConditionRouteDTO dto = new ConditionRouteDTO();
+ dto.setService(service);
+ dto.setConditions(conditions);
+
+ ResponseEntity<String> responseEntity = restTemplate.postForEntity(
+ url("/api/{env}/rules/route/condition"), dto, String.class, env
+ );
+ assertThat(responseEntity.getStatusCode(), is(HttpStatus.CREATED));
+
+ dto.setApplication(application);
+ when(providerService.findVersionInApplication(dto.getApplication())).thenReturn("2.7");
+
+ responseEntity = restTemplate.postForEntity(
+ url("/api/{env}/rules/route/condition"), dto, String.class, env
+ );
+ assertThat(responseEntity.getStatusCode(), is(HttpStatus.CREATED));
+ }
+
+ @Test
+ public void shouldUpdateRule() throws Exception {
+ String service = "org.apache.dubbo.demo.DemoService";
+ String content = "conditions:\n"
+ + "- => host != 172.22.3.111\n"
+ + "- => host != 172.22.3.112\n"
+ + "enabled: true\n"
+ + "force: true\n"
+ + "key: " + service + "\n"
+ + "priority: 0\n"
+ + "runtime: false\n"
+ + "scope: service";
+ String path = "/dubbo/config/" + service + "/condition-router";
+ zkClient.create().creatingParentContainersIfNeeded().forPath(path);
+ zkClient.setData().forPath(path, content.getBytes());
+
+ List<String> newConditions = Arrays.asList("=> host != 172.22.3.211", "=> host != 172.22.3.212");
+
+ ConditionRouteDTO dto = new ConditionRouteDTO();
+ dto.setConditions(newConditions);
+ dto.setService(service);
+
+ ResponseEntity<String> responseEntity = restTemplate.exchange(
+ url("/api/{env}/rules/route/condition/{service}"), HttpMethod.PUT,
+ new HttpEntity<>(dto, null), String.class, env, service
+ );
+ assertThat(responseEntity.getStatusCode(), is(HttpStatus.OK));
+
+ byte[] bytes = zkClient.getData().forPath(path);
+ String updatedConfig = new String(bytes);
+ RoutingRule rule = YamlParser.loadObject(updatedConfig, RoutingRule.class);
+ assertThat(rule.getConditions(), containsInAnyOrder(newConditions.toArray()));
+ }
+
+ @Test
+ public void shouldGetServiceRule() throws Exception {
+ String service = "org.apache.dubbo.demo.DemoService";
+ String content = "conditions:\n"
+ + "- => host != 172.22.3.111\n"
+ + "- => host != 172.22.3.112\n"
+ + "enabled: true\n"
+ + "force: true\n"
+ + "key: " + service + "\n"
+ + "priority: 0\n"
+ + "runtime: false\n"
+ + "scope: service";
+ String path = "/dubbo/config/" + service + "/condition-router";
+ zkClient.create().creatingParentContainersIfNeeded().forPath(path);
+ zkClient.setData().forPath(path, content.getBytes());
+
+ ResponseEntity<List<ConditionRouteDTO>> responseEntity = restTemplate.exchange(
+ url("/api/{env}/rules/route/condition/?service={service}"), HttpMethod.GET,
+ null, new ParameterizedTypeReference<List<ConditionRouteDTO>>() {
+ }, env, service
+ );
+ assertThat(responseEntity.getStatusCode(), is(HttpStatus.OK));
+ assertThat(responseEntity.getBody(), hasSize(1));
+ List<String> conditions = responseEntity.getBody()
+ .stream()
+ .flatMap(it -> it.getConditions().stream())
+ .collect(Collectors.toList());
+ assertThat(conditions, hasSize(2));
+ assertThat(conditions, containsInAnyOrder("=> host != 172.22.3.111", "=> host != 172.22.3.112"));
+ }
+
+ @Test
+ public void shouldDeleteRule() throws Exception {
+ String service = "org.apache.dubbo.demo.DemoService";
+ String content = "conditions:\n"
+ + "- => host != 172.22.3.111\n"
+ + "- => host != 172.22.3.112\n"
+ + "enabled: true\n"
+ + "force: true\n"
+ + "key: " + service + "\n"
+ + "priority: 0\n"
+ + "runtime: false\n"
+ + "scope: service";
+ String path = "/dubbo/config/" + service + "/condition-router";
+ zkClient.create().creatingParentContainersIfNeeded().forPath(path);
+ zkClient.setData().forPath(path, content.getBytes());
+
+ assertNotNull("zk path should not be null before deleting", zkClient.checkExists().forPath(path));
+
+ ResponseEntity<String> responseEntity = restTemplate.exchange(
+ url("/api/{env}/rules/route/condition/{service}"), HttpMethod.DELETE,
+ null, String.class, env, service
+ );
+ assertThat(responseEntity.getStatusCode(), is(HttpStatus.OK));
+
+ assertNull(zkClient.checkExists().forPath(path));
+ }
+
+ @Test
+ public void shouldThrowWhenDetailRouteWithUnknownId() {
+ ResponseEntity<String> responseEntity = restTemplate.getForEntity(
+ url("/api/{env}/rules/route/condition/{id}"), String.class, env, "non-existed-service"
+ );
+ assertThat(responseEntity.getStatusCode(), is(HttpStatus.NOT_FOUND));
+ }
+
+ @Test
+ public void shouldGetRouteDetail() throws Exception {
+ String service = "org.apache.dubbo.demo.DemoService";
+ String content = "conditions:\n"
+ + "- => host != 172.22.3.111\n"
+ + "- => host != 172.22.3.112\n"
+ + "enabled: true\n"
+ + "force: true\n"
+ + "key: " + service + "\n"
+ + "priority: 0\n"
+ + "runtime: false\n"
+ + "scope: service";
+ String path = "/dubbo/config/" + service + "/condition-router";
+ zkClient.create().creatingParentContainersIfNeeded().forPath(path);
+ zkClient.setData().forPath(path, content.getBytes());
+
+ ResponseEntity<ConditionRouteDTO> responseEntity = restTemplate.getForEntity(
+ url("/api/{env}/rules/route/condition/{id}"), ConditionRouteDTO.class, env, service
+ );
+ assertThat(responseEntity.getStatusCode(), is(HttpStatus.OK));
+
+ ConditionRouteDTO conditionRouteDTO = responseEntity.getBody();
+ assertNotNull(conditionRouteDTO);
+ assertThat(conditionRouteDTO.getConditions(), hasSize(2));
+ assertThat(conditionRouteDTO.getConditions(), containsInAnyOrder("=> host != 172.22.3.111", "=> host != 172.22.3.112"));
+ }
+
+ @Test
+ public void shouldEnableRoute() throws Exception {
+ String service = "org.apache.dubbo.demo.DemoService";
+ String content = "conditions:\n"
+ + "- => host != 172.22.3.111\n"
+ + "- => host != 172.22.3.112\n"
+ + "enabled: false\n"
+ + "force: true\n"
+ + "key: " + service + "\n"
+ + "priority: 0\n"
+ + "runtime: false\n"
+ + "scope: service";
+ String path = "/dubbo/config/" + service + "/condition-router";
+ zkClient.create().creatingParentContainersIfNeeded().forPath(path);
+ zkClient.setData().forPath(path, content.getBytes());
+
+ byte[] bytes = zkClient.getData().forPath(path);
+ String updatedConfig = new String(bytes);
+ RoutingRule rule = YamlParser.loadObject(updatedConfig, RoutingRule.class);
+ assertFalse(rule.isEnabled());
+
+ restTemplate.put(url("/api/{env}/rules/route/condition/enable/{id}"), null, env, service);
+
+ bytes = zkClient.getData().forPath(path);
+ updatedConfig = new String(bytes);
+ rule = YamlParser.loadObject(updatedConfig, RoutingRule.class);
+ assertTrue(rule.isEnabled());
+ }
+
+ @Test
+ public void shouldDisableRoute() throws Exception {
+ String service = "org.apache.dubbo.demo.DemoService";
+ String content = "conditions:\n"
+ + "- => host != 172.22.3.111\n"
+ + "- => host != 172.22.3.112\n"
+ + "enabled: true\n"
+ + "force: false\n"
+ + "key: " + service + "\n"
+ + "priority: 0\n"
+ + "runtime: false\n"
+ + "scope: service";
+ String path = "/dubbo/config/" + service + "/condition-router";
+ zkClient.create().creatingParentContainersIfNeeded().forPath(path);
+ zkClient.setData().forPath(path, content.getBytes());
+
+ byte[] bytes = zkClient.getData().forPath(path);
+ String updatedConfig = new String(bytes);
+ RoutingRule rule = YamlParser.loadObject(updatedConfig, RoutingRule.class);
+ assertTrue(rule.isEnabled());
+
+ restTemplate.put(url("/api/{env}/rules/route/condition/disable/{id}"), null, env, service);
+
+ bytes = zkClient.getData().forPath(path);
+ updatedConfig = new String(bytes);
+ rule = YamlParser.loadObject(updatedConfig, RoutingRule.class);
+ assertFalse(rule.isEnabled());
+ }
+}
diff --git a/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/controller/ManagementControllerTest.java b/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/controller/ManagementControllerTest.java
new file mode 100644
index 0000000..f4114ba
--- /dev/null
+++ b/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/controller/ManagementControllerTest.java
@@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.controller;
+
+import java.util.UUID;
+import org.apache.dubbo.admin.AbstractSpringIntegrationTest;
+import org.apache.dubbo.admin.common.util.Constants;
+import org.apache.dubbo.admin.model.dto.ConfigDTO;
+import org.apache.dubbo.admin.service.ProviderService;
+import org.junit.Test;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.hamcrest.Matchers.hasSize;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.when;
+
+public class ManagementControllerTest extends AbstractSpringIntegrationTest {
+ private final String env = "whatever";
+
+ @MockBean
+ private ProviderService providerService;
+
+ @Test
+ public void shouldCreateGlobalConfig() throws Exception {
+ ConfigDTO configDTO = new ConfigDTO();
+ configDTO.setKey(Constants.GLOBAL_CONFIG);
+ configDTO.setConfig("key1=val1\nkey2=val2");
+ ResponseEntity<Boolean> responseEntity = restTemplate.postForEntity(
+ url("/api/{env}/manage/config"), configDTO, Boolean.class, env
+ );
+ assertEquals(responseEntity.getStatusCode(), HttpStatus.CREATED);
+ assertEquals(responseEntity.getBody(), true);
+
+ byte[] bytes = zkClient.getData().forPath(getPath("dubbo"));
+ String config = new String(bytes);
+ assertEquals(configDTO.getConfig(), config);
+
+ zkClient.delete().forPath(getPath("dubbo"));
+ }
+
+ @Test
+ public void shouldCreateApplicationConfig() throws Exception {
+ String uuid = UUID.randomUUID().toString();
+ String application = "dubbo-admin" + uuid;
+ ConfigDTO configDTO = new ConfigDTO();
+ configDTO.setKey(application);
+ configDTO.setConfig("key1=val1\nkey2=val2");
+ ResponseEntity<Boolean> responseEntity = restTemplate.postForEntity(
+ url("/api/{env}/manage/config"), configDTO, Boolean.class, env
+ );
+ assertEquals(responseEntity.getStatusCode(), HttpStatus.CREATED);
+ assertEquals(responseEntity.getBody(), true);
+
+ byte[] bytes = zkClient.getData().forPath(getPath(application));
+ String config = new String(bytes);
+ assertEquals(configDTO.getConfig(), config);
+ }
+
+ @Test
+ public void shouldThrowWhenUpdateNonExistedConfigKey() {
+ ConfigDTO configDTO = new ConfigDTO();
+ configDTO.setKey(Constants.GLOBAL_CONFIG);
+ configDTO.setConfig("key1=val1\nkey2=val2");
+ ResponseEntity<Void> responseEntity = restTemplate.exchange(
+ url("/api/{env}/manage/config/{key}"), HttpMethod.PUT,
+ new HttpEntity<>(configDTO), Void.class, env, "non-existed"
+ );
+ assertEquals(responseEntity.getStatusCode(), HttpStatus.NOT_FOUND);
+ }
+
+ @Test
+ public void shouldUpdateConfigSpecifiedKey() throws Exception {
+ String key = "shouldUpdateConfigSpecifiedKey";
+ ConfigDTO configDTO = new ConfigDTO();
+ configDTO.setKey(key);
+ configDTO.setConfig("key1=val1\nkey2=val2");
+ restTemplate.postForEntity(url("/api/{env}/manage/config"), configDTO, Boolean.class, env);
+
+ configDTO.setConfig("key1=updatedVal1\nkey2=updatedVal2");
+ ResponseEntity<Void> responseEntity = restTemplate.exchange(
+ url("/api/{env}/manage/config/{key}"), HttpMethod.PUT,
+ new HttpEntity<>(configDTO), Void.class, env, key
+ );
+ assertEquals(responseEntity.getStatusCode(), HttpStatus.OK);
+
+ byte[] bytes = zkClient.getData().forPath(getPath(key));
+ String config = new String(bytes);
+ assertEquals("key1=updatedVal1\nkey2=updatedVal2", config);
+ }
+
+ @Test
+ public void shouldGetAllConfig() throws Exception {
+ int num = 20;
+ List<ConfigDTO> configDTOs = new ArrayList<>(num);
+ for (int i = 0; i < num; i++) {
+ ConfigDTO configDTO = new ConfigDTO();
+ configDTO.setKey("key" + i);
+ configDTO.setConfig("key1=val1\nkey2=val2");
+ configDTOs.add(configDTO);
+
+ String path = getPath(configDTO.getKey());
+ if (zkClient.checkExists().forPath(path) == null) {
+ zkClient.create().creatingParentsIfNeeded().forPath(path);
+ }
+ zkClient.setData().forPath(path, configDTO.getConfig().getBytes());
+ }
+ when(providerService.findApplications())
+ .thenReturn(configDTOs.stream().map(ConfigDTO::getKey).collect(Collectors.toSet()));
+
+ ResponseEntity<List<ConfigDTO>> responseEntity = restTemplate.exchange(
+ url("/api/{env}/manage/config/{key}"), HttpMethod.GET,
+ null, new ParameterizedTypeReference<List<ConfigDTO>>() {
+ }, env, "*"
+ );
+ assertEquals(responseEntity.getStatusCode(), HttpStatus.OK);
+ assertThat(responseEntity.getBody(), hasSize(num));
+ }
+
+ @Test
+ public void shouldDeleteConfig() throws Exception {
+ int num = 20;
+ List<ConfigDTO> configDTOs = new ArrayList<>(num);
+ for (int i = 0; i < num; i++) {
+ ConfigDTO configDTO = new ConfigDTO();
+ configDTO.setKey("shouldDeleteConfigKey" + i);
+ configDTO.setConfig("key1=val1\nkey2=val2");
+ configDTOs.add(configDTO);
+
+ String path = getPath(configDTO.getKey());
+ if (zkClient.checkExists().forPath(path) == null) {
+ zkClient.create().creatingParentsIfNeeded().forPath(path);
+ }
+ zkClient.setData().forPath(path, configDTO.getConfig().getBytes());
+ }
+ when(providerService.findApplications())
+ .thenReturn(configDTOs.stream().map(ConfigDTO::getKey).collect(Collectors.toSet()));
+
+ restTemplate.delete(url("/api/{env}/manage/config/{key}"), env, "shouldDeleteConfigKey1");
+ ResponseEntity<List<ConfigDTO>> responseEntity = restTemplate.exchange(
+ url("/api/{env}/manage/config/{key}"), HttpMethod.GET,
+ null, new ParameterizedTypeReference<List<ConfigDTO>>() {
+ }, env, "*"
+ );
+ assertEquals(responseEntity.getStatusCode(), HttpStatus.OK);
+ assertThat(responseEntity.getBody(), hasSize(num - 1));
+
+ restTemplate.delete(url("/api/{env}/manage/config/{key}"), env, "shouldDeleteConfigKey10");
+ responseEntity = restTemplate.exchange(
+ url("/api/{env}/manage/config/{key}"), HttpMethod.GET,
+ null, new ParameterizedTypeReference<List<ConfigDTO>>() {
+ }, env, "*"
+ );
+ assertEquals(responseEntity.getStatusCode(), HttpStatus.OK);
+ assertThat(responseEntity.getBody(), hasSize(num - 2));
+ }
+
+ private String getPath(String key) {
+ return "/dubbo/" + Constants.CONFIG_KEY + Constants.PATH_SEPARATOR + key + Constants.PATH_SEPARATOR
+ + Constants.DUBBO_PROPERTY;
+ }
+}
diff --git a/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/controller/ServiceControllerTest.java b/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/controller/ServiceControllerTest.java
index 7518675..1d9be1a 100644
--- a/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/controller/ServiceControllerTest.java
+++ b/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/controller/ServiceControllerTest.java
@@ -25,7 +25,7 @@
import org.apache.dubbo.common.URL;
import org.apache.dubbo.registry.Registry;
import org.apache.dubbo.registry.support.AbstractRegistry;
-import org.junit.Before;
+import org.junit.After;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
@@ -40,11 +40,14 @@
@Autowired
private Registry registry;
- @Before
- public void setUp() throws InterruptedException {
+ @After
+ public void tearDown() throws Exception {
final Set<URL> registered = ((AbstractRegistry) registry).getRegistered();
for (final URL url : registered) {
- registry.unregister(url);
+ try {
+ registry.unregister(url);
+ } catch (Exception ignored) {
+ }
}
TimeUnit.SECONDS.sleep(1);
}
@@ -92,9 +95,9 @@
@Test
public void shouldFilterUsingPattern() throws InterruptedException {
final int num = 10;
+ final String application = "dubbo-admin";
for (int i = 0; i < num; i++) {
final String service = "org.apache.dubbo.admin.test.service" + i + ".pattern" + (i % 2);
- final String application = "dubbo-admin";
registry.register(generateProviderServiceUrl(application, service));
}
TimeUnit.SECONDS.sleep(1);
diff --git a/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/service/RegistryServerSyncTest.java b/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/service/RegistryServerSyncTest.java
new file mode 100644
index 0000000..45e2747
--- /dev/null
+++ b/dubbo-admin-backend/src/test/java/org/apache/dubbo/admin/service/RegistryServerSyncTest.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.service;
+
+import org.apache.dubbo.admin.common.util.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.registry.Registry;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+public class RegistryServerSyncTest {
+
+ @Mock
+ private Registry registry;
+
+ @InjectMocks
+ private RegistryServerSync registryServerSync;
+
+ @Test
+ public void testGetRegistryCache() {
+ registryServerSync.getRegistryCache();
+ }
+
+ @Test
+ public void testAfterPropertiesSet() throws Exception {
+ registryServerSync.afterPropertiesSet();
+ verify(registry).subscribe(any(URL.class), any(RegistryServerSync.class));
+ }
+
+ @Test
+ public void testDestroy() throws Exception {
+ registryServerSync.destroy();
+ verify(registry).unsubscribe(any(URL.class), any(RegistryServerSync.class));
+ }
+
+ @Test
+ public void testNotify() {
+ registryServerSync.notify(null);
+ registryServerSync.notify(Collections.emptyList());
+
+ // when url.getProtocol is not empty protocol
+ URL consumerUrl = mock(URL.class);
+ URL providerUrl = mock(URL.class);
+
+ when(consumerUrl.getParameter(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY)).thenReturn(org.apache.dubbo.common.Constants.CONSUMER_PROTOCOL);
+ when(consumerUrl.getServiceInterface()).thenReturn("org.apache.dubbo.consumer");
+ when(consumerUrl.getServiceKey()).thenReturn("org.apache.dubbo.consumer");
+ when(consumerUrl.toFullString()).thenReturn("consumer://192.168.1.10/sunbufu.dubbo.consumer?application=dubbo&category=consumer&check=false&dubbo=2.7.0&interface=sunbufu.dubbo.consumer&loadbalabce=roundrobin&mehods=sayHi,sayGoodBye&owner=sunbufu&pid=18&protocol=dubbo&side=consumer&timeout=3000×tamp=1548127407769");
+ when(providerUrl.getParameter(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY)).thenReturn(org.apache.dubbo.common.Constants.PROVIDER_PROTOCOL);
+ when(providerUrl.getServiceInterface()).thenReturn("org.apache.dubbo.provider");
+ when(providerUrl.getServiceKey()).thenReturn("org.apache.dubbo.provider");
+ when(providerUrl.toFullString()).thenReturn("consumer://192.168.1.10/sunbufu.dubbo.consumer?application=dubbo&category=consumer&check=false&dubbo=2.6.2&interface=sunbufu.dubbo.consumer&loadbalabce=roundrobin&mehods=sayHi,sayGoodBye&owner=sunbufu&pid=18&protocol=dubbo&side=consumer&timeout=3000×tamp=1548127407769");
+
+ registryServerSync.notify(Arrays.asList(consumerUrl, consumerUrl, providerUrl));
+
+ ConcurrentMap<String, Map<String, URL>> consumerMap = registryServerSync.getRegistryCache().get(org.apache.dubbo.common.Constants.CONSUMER_PROTOCOL);
+ assertTrue(consumerMap.keySet().contains("org.apache.dubbo.consumer"));
+ ConcurrentMap<String, Map<String, URL>> providerMap = registryServerSync.getRegistryCache().get(org.apache.dubbo.common.Constants.PROVIDER_PROTOCOL);
+ assertTrue(providerMap.keySet().contains("org.apache.dubbo.provider"));
+
+ // when url.getProtocol is empty protocol
+ when(consumerUrl.getProtocol()).thenReturn(org.apache.dubbo.common.Constants.EMPTY_PROTOCOL);
+ when(consumerUrl.getParameter(Constants.GROUP_KEY)).thenReturn("dubbo");
+ when(consumerUrl.getParameter(Constants.VERSION_KEY)).thenReturn("2.7.0");
+ registryServerSync.notify(Collections.singletonList(consumerUrl));
+
+ assertTrue(!consumerMap.keySet().contains("org.apache.dubbo.consumer"));
+
+ // when url's group or version is ANY_VALUE (*)
+ when(providerUrl.getProtocol()).thenReturn(org.apache.dubbo.common.Constants.EMPTY_PROTOCOL);
+ when(providerUrl.getParameter(Constants.GROUP_KEY)).thenReturn(Constants.ANY_VALUE);
+ registryServerSync.notify(Collections.singletonList(providerUrl));
+
+ assertTrue(!providerMap.keySet().contains("org.apache.dubbo.provider"));
+ }
+}
\ No newline at end of file
diff --git a/dubbo-admin-frontend/src/components/ServiceSearch.vue b/dubbo-admin-frontend/src/components/ServiceSearch.vue
index 1ddb566..2f69ae2 100644
--- a/dubbo-admin-frontend/src/components/ServiceSearch.vue
+++ b/dubbo-admin-frontend/src/components/ServiceSearch.vue
@@ -25,7 +25,7 @@
<v-layout row wrap>
<v-combobox
id="serviceSearch"
- :loading="loading"
+ :loading="searchLoading"
:items="typeAhead"
:search-input.sync="input"
v-model="filter"
@@ -147,11 +147,9 @@
}
],
timerID: null,
- loading: false,
+ searchLoading: false,
selected: 0,
- serviceItem: [],
input: null,
- appItem: [],
typeAhead: [],
services: [],
filter: '',
@@ -220,17 +218,13 @@
// Simulated ajax query
this.timerID = setTimeout(() => {
if (v && v.length >= 4) {
- this.loading = true
+ this.searchLoading = true
if (this.selected === 0) {
- this.typeAhead = this.serviceItem.filter(e => {
- return (e || '').toLowerCase().indexOf((v || '').toLowerCase()) > -1
- })
+ this.typeAhead = this.$store.getters.getServiceItems(v)
} else if (this.selected === 2) {
- this.typeAhead = this.appItem.filter(e => {
- return (e || '').toLowerCase().indexOf((v || '').toLowerCase()) > -1
- })
+ this.typeAhead = this.$store.getters.getAppItems(v)
}
- this.loading = false
+ this.searchLoading = false
this.timerID = null
} else {
this.typeAhead = []
@@ -286,10 +280,11 @@
},
mounted: function () {
this.setHeaders()
+ this.$store.dispatch('loadServiceItems')
+ this.$store.dispatch('loadAppItems')
let query = this.$route.query
let filter = null
let pattern = null
- let vm = this
Object.keys(query).forEach(function (key) {
if (key === 'filter') {
filter = query[key]
@@ -315,19 +310,6 @@
pattern = 'service'
this.search(this.filter, pattern, true)
}
- this.$axios.get('/services')
- .then(response => {
- if (response.status === 200) {
- vm.serviceItem = response.data
- }
- })
-
- this.$axios.get('/applications')
- .then(response => {
- if (response.status === 200) {
- vm.appItem = response.data
- }
- })
}
}
diff --git a/dubbo-admin-frontend/src/components/governance/AccessControl.vue b/dubbo-admin-frontend/src/components/governance/AccessControl.vue
index 0c59e0d..d4480ea 100644
--- a/dubbo-admin-frontend/src/components/governance/AccessControl.vue
+++ b/dubbo-admin-frontend/src/components/governance/AccessControl.vue
@@ -26,6 +26,10 @@
<v-combobox
id="serviceSearch"
v-model="filter"
+ :loading="searchLoading"
+ :items="typeAhead"
+ :search-input.sync="input"
+ @keyup.enter="search"
flat
append-icon=""
hide-no-data
@@ -240,6 +244,10 @@
serviceHeaders: [],
appHeaders: [],
accesses: [],
+ searchLoading: false,
+ typeAhead: [],
+ input: null,
+ timerID: null,
modal: {
enable: false,
readonly: false,
@@ -303,6 +311,26 @@
}
]
},
+ querySelections (v) {
+ if (this.timerID) {
+ clearTimeout(this.timerID)
+ }
+ // Simulated ajax query
+ this.timerID = setTimeout(() => {
+ if (v && v.length >= 4) {
+ this.searchLoading = true
+ if (this.selected === 0) {
+ this.typeAhead = this.$store.getters.getServiceItems(v)
+ } else if (this.selected === 1) {
+ this.typeAhead = this.$store.getters.getAppItems(v)
+ }
+ this.searchLoading = false
+ this.timerID = null
+ } else {
+ this.typeAhead = []
+ }
+ }, 500)
+ },
search () {
if (!this.filter) {
this.filter = document.querySelector('#serviceSearch').value.trim()
@@ -468,6 +496,9 @@
}
},
watch: {
+ input (val) {
+ this.querySelections(val)
+ },
area () {
this.setAppHeaders()
this.setServiceHeaders()
@@ -476,6 +507,8 @@
mounted () {
this.setAppHeaders()
this.setServiceHeaders()
+ this.$store.dispatch('loadServiceItems')
+ this.$store.dispatch('loadAppItems')
let query = this.$route.query
if ('service' in query) {
this.filter = query['service']
diff --git a/dubbo-admin-frontend/src/components/governance/LoadBalance.vue b/dubbo-admin-frontend/src/components/governance/LoadBalance.vue
index 7db8fad..42771d9 100644
--- a/dubbo-admin-frontend/src/components/governance/LoadBalance.vue
+++ b/dubbo-admin-frontend/src/components/governance/LoadBalance.vue
@@ -25,6 +25,10 @@
<v-layout row wrap>
<v-combobox
id="serviceSearch"
+ :loading="searchLoading"
+ :items="typeAhead"
+ :search-input.sync="input"
+ @keyup.enter="submit"
v-model="filter"
flat
append-icon=""
@@ -198,6 +202,10 @@
warnText: '',
warnStatus: {},
height: 0,
+ searchLoading: false,
+ typeAhead: [],
+ input: null,
+ timerID: null,
operations: [
{id: 0, icon: 'visibility', tooltip: 'view'},
{id: 1, icon: 'edit', tooltip: 'edit'},
@@ -274,6 +282,26 @@
}
]
},
+ querySelections (v) {
+ if (this.timerID) {
+ clearTimeout(this.timerID)
+ }
+ // Simulated ajax query
+ this.timerID = setTimeout(() => {
+ if (v && v.length >= 4) {
+ this.searchLoading = true
+ if (this.selected === 0) {
+ this.typeAhead = this.$store.getters.getServiceItems(v)
+ } else if (this.selected === 1) {
+ this.typeAhead = this.$store.getters.getAppItems(v)
+ }
+ this.searchLoading = false
+ this.timerID = null
+ } else {
+ this.typeAhead = []
+ }
+ }, 500)
+ },
submit: function () {
this.filter = document.querySelector('#serviceSearch').value.trim()
this.search(this.filter, true)
@@ -448,6 +476,9 @@
}
},
watch: {
+ input (val) {
+ this.querySelections(val)
+ },
area () {
this.setServiceHeaders()
this.setAppHeaders()
@@ -456,6 +487,8 @@
mounted: function () {
this.setServiceHeaders()
this.setAppHeaders()
+ this.$store.dispatch('loadServiceItems')
+ this.$store.dispatch('loadAppItems')
this.ruleText = this.template
let query = this.$route.query
let filter = null
diff --git a/dubbo-admin-frontend/src/components/governance/Overrides.vue b/dubbo-admin-frontend/src/components/governance/Overrides.vue
index b2bedc6..d2f48b6 100644
--- a/dubbo-admin-frontend/src/components/governance/Overrides.vue
+++ b/dubbo-admin-frontend/src/components/governance/Overrides.vue
@@ -26,6 +26,10 @@
<v-combobox
id="serviceSearch"
v-model="filter"
+ :loading="searchLoading"
+ :items="typeAhead"
+ :search-input.sync="input"
+ @keyup.enter="submit"
flat
append-icon=""
hide-no-data
@@ -180,6 +184,10 @@
warnStatus: {},
height: 0,
operations: operations,
+ searchLoading: false,
+ typeAhead: [],
+ input: null,
+ timerID: null,
serviceConfigs: [
],
appConfigs: [
@@ -229,6 +237,26 @@
}
]
},
+ querySelections (v) {
+ if (this.timerID) {
+ clearTimeout(this.timerID)
+ }
+ // Simulated ajax query
+ this.timerID = setTimeout(() => {
+ if (v && v.length >= 4) {
+ this.searchLoading = true
+ if (this.selected === 0) {
+ this.typeAhead = this.$store.getters.getServiceItems(v)
+ } else if (this.selected === 1) {
+ this.typeAhead = this.$store.getters.getAppItems(v)
+ }
+ this.searchLoading = false
+ this.timerID = null
+ } else {
+ this.typeAhead = []
+ }
+ }, 500)
+ },
submit: function () {
this.filter = document.querySelector('#serviceSearch').value.trim()
this.search(this.filter, true)
@@ -435,6 +463,9 @@
}
},
watch: {
+ input (val) {
+ this.querySelections(val)
+ },
area () {
this.setAppHeaders()
this.setServiceHeaders()
@@ -443,6 +474,8 @@
mounted: function () {
this.setAppHeaders()
this.setServiceHeaders()
+ this.$store.dispatch('loadServiceItems')
+ this.$store.dispatch('loadAppItems')
this.ruleText = this.template
let query = this.$route.query
let filter = null
diff --git a/dubbo-admin-frontend/src/components/governance/RoutingRule.vue b/dubbo-admin-frontend/src/components/governance/RoutingRule.vue
index 5f95b4e..a033c4b 100644
--- a/dubbo-admin-frontend/src/components/governance/RoutingRule.vue
+++ b/dubbo-admin-frontend/src/components/governance/RoutingRule.vue
@@ -26,6 +26,10 @@
<v-combobox
id="serviceSearch"
v-model="filter"
+ :loading="searchLoading"
+ :items="typeAhead"
+ :search-input.sync="input"
+ @keyup.enter="submit"
flat
append-icon=""
hide-no-data
@@ -179,6 +183,10 @@
warnText: '',
warnStatus: {},
height: 0,
+ searchLoading: false,
+ typeAhead: [],
+ input: null,
+ timerID: null,
operations: operations,
serviceRoutingRules: [
],
@@ -242,6 +250,26 @@
}
]
},
+ querySelections (v) {
+ if (this.timerID) {
+ clearTimeout(this.timerID)
+ }
+ // Simulated ajax query
+ this.timerID = setTimeout(() => {
+ if (v && v.length >= 4) {
+ this.searchLoading = true
+ if (this.selected === 0) {
+ this.typeAhead = this.$store.getters.getServiceItems(v)
+ } else if (this.selected === 1) {
+ this.typeAhead = this.$store.getters.getAppItems(v)
+ }
+ this.searchLoading = false
+ this.timerID = null
+ } else {
+ this.typeAhead = []
+ }
+ }, 500)
+ },
submit: function () {
this.filter = document.querySelector('#serviceSearch').value.trim()
this.search(this.filter, true)
@@ -443,6 +471,9 @@
}
},
watch: {
+ input (val) {
+ this.querySelections(val)
+ },
area () {
this.setAppHeaders()
this.setServiceHeaders()
@@ -451,6 +482,8 @@
mounted: function () {
this.setAppHeaders()
this.setServiceHeaders()
+ this.$store.dispatch('loadServiceItems')
+ this.$store.dispatch('loadAppItems')
this.ruleText = this.template
let query = this.$route.query
let filter = null
diff --git a/dubbo-admin-frontend/src/components/governance/WeightAdjust.vue b/dubbo-admin-frontend/src/components/governance/WeightAdjust.vue
index 0bbcf5f..8f266c2 100644
--- a/dubbo-admin-frontend/src/components/governance/WeightAdjust.vue
+++ b/dubbo-admin-frontend/src/components/governance/WeightAdjust.vue
@@ -26,6 +26,10 @@
<v-combobox
id="serviceSearch"
v-model="filter"
+ :items="typeAhead"
+ :search-input.sync="input"
+ :loading="searchLoading"
+ @keyup.enter="submit"
flat
append-icon=""
hide-no-data
@@ -196,6 +200,10 @@
warnText: '',
warnStatus: {},
height: 0,
+ searchLoading: false,
+ typeAhead: [],
+ input: null,
+ timerID: null,
operations: [
{id: 0, icon: 'visibility', tooltip: 'view'},
{id: 1, icon: 'edit', tooltip: 'edit'},
@@ -239,6 +247,26 @@
}
]
},
+ querySelections (v) {
+ if (this.timerID) {
+ clearTimeout(this.timerID)
+ }
+ // Simulated ajax query
+ this.timerID = setTimeout(() => {
+ if (v && v.length >= 4) {
+ this.searchLoading = true
+ if (this.selected === 0) {
+ this.typeAhead = this.$store.getters.getServiceItems(v)
+ } else if (this.selected === 1) {
+ this.typeAhead = this.$store.getters.getAppItems(v)
+ }
+ this.searchLoading = false
+ this.timerID = null
+ } else {
+ this.typeAhead = []
+ }
+ }, 500)
+ },
setAppHeaders: function () {
this.appHeaders = [
{
@@ -427,11 +455,16 @@
area () {
this.setAppHeaders()
this.setServiceHeaders()
+ },
+ input (val) {
+ this.querySelections(val)
}
},
mounted: function () {
this.setAppHeaders()
this.setServiceHeaders()
+ this.$store.dispatch('loadServiceItems')
+ this.$store.dispatch('loadAppItems')
this.ruleText = this.template
let query = this.$route.query
let filter = null
diff --git a/dubbo-admin-frontend/src/store/index.js b/dubbo-admin-frontend/src/store/index.js
index a631f4d..f894271 100644
--- a/dubbo-admin-frontend/src/store/index.js
+++ b/dubbo-admin-frontend/src/store/index.js
@@ -23,17 +23,66 @@
export const store = new Vuex.Store({
state: {
appTitle: 'Dubbo OPS',
- area: null
+ area: null,
+ serviceItems: null,
+ appItems: null
},
mutations: {
setArea (state, area) {
state.area = area
+ },
+ setServiceItems (state, serviceItems) {
+ state.serviceItems = serviceItems
+ },
+ setAppItems (state, appItems) {
+ state.appItems = appItems
}
},
actions: {
changeArea ({commit}, area) {
commit('setArea', area)
+ },
+ /**
+ * Load service items from server, put results into storage.
+ */
+ loadServiceItems ({commit}) {
+ Vue.prototype.$axios.get('/services')
+ .then(response => {
+ if (response.status === 200) {
+ const serviceItems = response.data
+ commit('setServiceItems', serviceItems)
+ }
+ })
+ },
+ /**
+ * Load application items from server, put results into storage.
+ */
+ loadAppItems ({commit}) {
+ Vue.prototype.$axios.get('/applications')
+ .then(response => {
+ if (response.status === 200) {
+ const appItems = response.data
+ commit('setAppItems', appItems)
+ }
+ })
}
},
- getters: {}
+ getters: {
+ /**
+ * Get service item arrays with filter
+ */
+ getServiceItems: (state) => (filter) => {
+ return state.serviceItems.filter(e => {
+ return (e || '').toLowerCase().indexOf((filter || '').toLowerCase()) > -1
+ })
+ },
+ /**
+ * Get application item arrays with filter
+ */
+ getAppItems: (state) => (filter) => {
+ return state.appItems.filter(e => {
+ return (e || '').toLowerCase().indexOf((filter || '').toLowerCase()) > -1
+ })
+ }
+ }
})
diff --git a/mvnw b/mvnw
new file mode 100755
index 0000000..5551fde
--- /dev/null
+++ b/mvnw
@@ -0,0 +1,286 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven2 Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# M2_HOME - location of maven2's installed home dir
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+ if [ -f /etc/mavenrc ] ; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ] ; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "`uname`" in
+ CYGWIN*) cygwin=true ;;
+ MINGW*) mingw=true;;
+ Darwin*) darwin=true
+ # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+ # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+ if [ -z "$JAVA_HOME" ]; then
+ if [ -x "/usr/libexec/java_home" ]; then
+ export JAVA_HOME="`/usr/libexec/java_home`"
+ else
+ export JAVA_HOME="/Library/Java/Home"
+ fi
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+ if [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=`java-config --jre-home`
+ fi
+fi
+
+if [ -z "$M2_HOME" ] ; then
+ ## resolve links - $0 may be a link to maven's home
+ PRG="$0"
+
+ # need this for relative symlinks
+ while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG="`dirname "$PRG"`/$link"
+ fi
+ done
+
+ saveddir=`pwd`
+
+ M2_HOME=`dirname "$PRG"`/..
+
+ # make it fully qualified
+ M2_HOME=`cd "$M2_HOME" && pwd`
+
+ cd "$saveddir"
+ # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --unix "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME="`(cd "$M2_HOME"; pwd)`"
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+ # TODO classpath?
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="`which javac`"
+ if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=`which readlink`
+ if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
+ if $darwin ; then
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
+ else
+ javaExecutable="`readlink -f \"$javaExecutable\"`"
+ fi
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="`which java`"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+ echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+
+ if [ -z "$1" ]
+ then
+ echo "Path not specified to find_maven_basedir"
+ return 1
+ fi
+
+ basedir="$1"
+ wdir="$1"
+ while [ "$wdir" != '/' ] ; do
+ if [ -d "$wdir"/.mvn ] ; then
+ basedir=$wdir
+ break
+ fi
+ # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+ if [ -d "${wdir}" ]; then
+ wdir=`cd "$wdir/.."; pwd`
+ fi
+ # end of workaround
+ done
+ echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ echo "$(tr -s '\n' ' ' < "$1")"
+ fi
+}
+
+BASE_DIR=`find_maven_basedir "$(pwd)"`
+if [ -z "$BASE_DIR" ]; then
+ exit 1;
+fi
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found .mvn/wrapper/maven-wrapper.jar"
+ fi
+else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+ fi
+ jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
+ while IFS="=" read key value; do
+ case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
+ esac
+ done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Downloading from: $jarUrl"
+ fi
+ wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+
+ if command -v wget > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found wget ... using wget"
+ fi
+ wget "$jarUrl" -O "$wrapperJarPath"
+ elif command -v curl > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found curl ... using curl"
+ fi
+ curl -o "$wrapperJarPath" "$jarUrl"
+ else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Falling back to using Java to download"
+ fi
+ javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+ if [ -e "$javaClass" ]; then
+ if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Compiling MavenWrapperDownloader.java ..."
+ fi
+ # Compiling the Java class
+ ("$JAVA_HOME/bin/javac" "$javaClass")
+ fi
+ if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ # Running the downloader
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Running MavenWrapperDownloader.java ..."
+ fi
+ ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+ fi
+ fi
+ fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+ echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --path --windows "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+ [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+ MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
+fi
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
diff --git a/mvnw.cmd b/mvnw.cmd
new file mode 100755
index 0000000..e5cfb0a
--- /dev/null
+++ b/mvnw.cmd
@@ -0,0 +1,161 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven2 Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
+if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
+FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO (
+ IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+ echo Found %WRAPPER_JAR%
+) else (
+ echo Couldn't find %WRAPPER_JAR%, downloading it ...
+ echo Downloading from: %DOWNLOAD_URL%
+ powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"
+ echo Finished downloading %WRAPPER_JAR%
+)
+@REM End of extension
+
+%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
+if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%" == "on" pause
+
+if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
+
+exit /B %ERROR_CODE%
diff --git a/pom.xml b/pom.xml
index 80a82b0..e1efff0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -66,6 +66,7 @@
<jedis-version>2.9.0</jedis-version>
<apollo-version>1.2.0</apollo-version>
<snakeyaml-version>1.19</snakeyaml-version>
+ <maven-checkstyle-plugin-version>3.0.0</maven-checkstyle-plugin-version>
</properties>
<dependencyManagement>
@@ -146,6 +147,46 @@
</dependencies>
</dependencyManagement>
+ <profiles>
+ <profile>
+ <id>checkstyle</id>
+ <activation>
+ <jdk>[1.8,)</jdk>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <version>${maven-checkstyle-plugin-version}</version>
+ <dependencies>
+ <dependency>
+ <groupId>com.puppycrawl.tools</groupId>
+ <artifactId>checkstyle</artifactId>
+ <version>8.9</version>
+ </dependency>
+ </dependencies>
+ <executions>
+ <execution>
+ <id>checkstyle-validation</id>
+ <phase>validate</phase>
+ <configuration>
+ <configLocation>codestyle/checkstyle.xml</configLocation>
+ <encoding>UTF-8</encoding>
+ <consoleOutput>true</consoleOutput>
+ <failOnViolation>true</failOnViolation>
+ </configuration>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
<build>
<plugins>
<plugin>