From 0904bdd5e8c2083402ecefaafe634c3eef5f493b Mon Sep 17 00:00:00 2001 From: haoyann <1064645534@qq.com> Date: Tue, 31 Aug 2021 11:19:57 +0800 Subject: [PATCH 1/4] application discover support --- dubbo-admin-server/pom.xml | 13 +- .../dubbo/admin/common/util/Constants.java | 1 + .../admin/common/util/ServiceTestUtil.java | 8 +- .../admin/common/util/ServiceTestV3Util.java | 236 ++++++++++++++++ .../dubbo/admin/common/util/SyncUtils.java | 13 +- .../dubbo/admin/config/ConfigCenter.java | 38 ++- .../admin/controller/MeshRouteController.java | 13 +- .../admin/controller/ServiceController.java | 18 +- .../controller/ServiceTestController.java | 31 ++- .../model/domain/FullServiceDefinition.java | 41 +++ .../admin/model/domain/MethodDefinition.java | 108 ++++++++ .../dubbo/admin/model/domain/Provider.java | 10 + .../admin/model/domain/RegistrySource.java | 26 ++ .../admin/model/domain/ServiceDefinition.java | 133 +++++++++ .../admin/model/domain/TypeDefinition.java | 161 +++++++++++ .../dubbo/admin/model/dto/ServiceDTO.java | 19 +- .../admin/model/dto/ServiceDetailDTO.java | 7 +- .../mapping/AddressChangeListener.java | 32 +++ .../mapping/AdminMappingListener.java | 131 +++++++++ .../AdminServiceInstancesChangedListener.java | 50 ++++ .../registry/mapping/ServiceMapping.java | 36 +++ .../mapping/impl/NoOpServiceMapping.java | 40 +++ .../mapping/impl/ZookeeperServiceMapping.java | 93 +++++++ .../dubbo/admin/service/ProviderService.java | 39 +-- .../dubbo/admin/service/RegistryCache.java | 48 ++++ .../admin/service/RegistryServerSync.java | 29 +- .../admin/service/impl/AbstractService.java | 7 +- .../service/impl/ConsumerServiceImpl.java | 8 +- .../service/impl/InstanceRegistryCache.java | 55 ++++ .../impl/InstanceRegistryQueryHelper.java | 156 +++++++++++ .../service/impl/InterfaceRegistryCache.java | 51 ++++ .../service/impl/ProviderServiceImpl.java | 252 +++--------------- ...ubbo.admin.registry.mapping.ServiceMapping | 1 + .../admin/service/RegistryServerSyncTest.java | 35 ++- .../src/components/ServiceDetail.vue | 14 + .../src/components/ServiceSearch.vue | 22 +- .../src/components/governance/MeshRule.vue | 2 +- dubbo-admin-ui/src/lang/en.js | 3 + dubbo-admin-ui/src/lang/zh.js | 3 + dubbo-admin-ui/src/store/index.js | 12 + pom.xml | 20 +- 41 files changed, 1703 insertions(+), 312 deletions(-) create mode 100644 dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestV3Util.java create mode 100644 dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/FullServiceDefinition.java create mode 100644 dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/MethodDefinition.java create mode 100644 dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/RegistrySource.java create mode 100644 dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/ServiceDefinition.java create mode 100644 dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/TypeDefinition.java create mode 100644 dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AddressChangeListener.java create mode 100644 dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AdminMappingListener.java create mode 100644 dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AdminServiceInstancesChangedListener.java create mode 100644 dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/ServiceMapping.java create mode 100644 dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/impl/NoOpServiceMapping.java create mode 100644 dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/impl/ZookeeperServiceMapping.java create mode 100644 dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/RegistryCache.java create mode 100644 dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InstanceRegistryCache.java create mode 100644 dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InstanceRegistryQueryHelper.java create mode 100644 dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InterfaceRegistryCache.java create mode 100644 dubbo-admin-server/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.admin.registry.mapping.ServiceMapping diff --git a/dubbo-admin-server/pom.xml b/dubbo-admin-server/pom.xml index e13d213f5..cb3ae75a8 100644 --- a/dubbo-admin-server/pom.xml +++ b/dubbo-admin-server/pom.xml @@ -123,6 +123,11 @@ org.apache.curator curator-recipes + + org.apache.curator + curator-x-discovery + + com.alibaba fastjson @@ -167,10 +172,10 @@ netty-all - - org.apache.dubbo - dubbo-serialization-kryo - + + + + org.mockito diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/Constants.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/Constants.java index 96e3f2449..aa694b74b 100644 --- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/Constants.java +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/Constants.java @@ -80,6 +80,7 @@ public class Constants { public static final Set CONFIGS = new HashSet<>(); public static final String COLON = ":"; public static final String MESH_RULE_SUFFIX = ".MESHAPPRULE"; + public static final String DEFAULT_MAPPING_GROUP = "mapping"; static { CONFIGS.add(WEIGHT); CONFIGS.add(BALANCING); diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestUtil.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestUtil.java index fa568ff6c..5e94ae70f 100644 --- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestUtil.java +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestUtil.java @@ -19,10 +19,10 @@ import org.apache.commons.lang3.StringUtils; import org.apache.dubbo.admin.model.domain.MethodMetadata; -import org.apache.dubbo.metadata.definition.model.FullServiceDefinition; -import org.apache.dubbo.metadata.definition.model.MethodDefinition; -import org.apache.dubbo.metadata.definition.model.ServiceDefinition; -import org.apache.dubbo.metadata.definition.model.TypeDefinition; +import org.apache.dubbo.admin.model.domain.FullServiceDefinition; +import org.apache.dubbo.admin.model.domain.MethodDefinition; +import org.apache.dubbo.admin.model.domain.ServiceDefinition; +import org.apache.dubbo.admin.model.domain.TypeDefinition; import java.util.ArrayList; import java.util.Collections; diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestV3Util.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestV3Util.java new file mode 100644 index 000000000..3cc7b271e --- /dev/null +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/ServiceTestV3Util.java @@ -0,0 +1,236 @@ +/* + * 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.apache.dubbo.admin.model.domain.MethodMetadata; +import org.apache.dubbo.metadata.definition.model.FullServiceDefinition; +import org.apache.dubbo.metadata.definition.model.MethodDefinition; +import org.apache.dubbo.metadata.definition.model.ServiceDefinition; +import org.apache.dubbo.metadata.definition.model.TypeDefinition; + +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ServiceTestV3Util { + private static Pattern COLLECTION_PATTERN = Pattern.compile("^java\\.util\\..*(Set|List|Queue|Collection|Deque)(<.*>)*$"); + private static Pattern MAP_PATTERN = Pattern.compile("^java\\.util\\..*Map.*(<.*>)*$"); + + public static boolean sameMethod(MethodDefinition m, String methodSig) { + String name = m.getName(); + String[] parameters = m.getParameterTypes(); + StringBuilder sb = new StringBuilder(); + sb.append(name).append("~"); + for (String parameter : parameters) { + sb.append(parameter).append(";"); + } + String sig = StringUtils.removeEnd(sb.toString(), ";"); + return sig.equals(methodSig); + } + + public static MethodMetadata generateMethodMeta(FullServiceDefinition serviceDefinition, MethodDefinition methodDefinition) { + MethodMetadata methodMetadata = new MethodMetadata(); + String[] parameterTypes = methodDefinition.getParameterTypes(); + String returnType = methodDefinition.getReturnType(); + String signature = methodDefinition.getName() + "~" + String.join(";", parameterTypes); + methodMetadata.setSignature(signature); + methodMetadata.setReturnType(returnType); + List parameters = generateParameterTypes(parameterTypes, serviceDefinition); + methodMetadata.setParameterTypes(parameters); + return methodMetadata; + } + + private static boolean isPrimitiveType(TypeDefinition td) { + String type = td.getType(); + return isPrimitiveType(type); + } + + private static boolean isPrimitiveType(String type) { + return type.equals("byte") || type.equals("java.lang.Byte") || + type.equals("short") || type.equals("java.lang.Short") || + type.equals("int") || type.equals("java.lang.Integer") || + type.equals("long") || type.equals("java.lang.Long") || + type.equals("float") || type.equals("java.lang.Float") || + type.equals("double") || type.equals("java.lang.Double") || + type.equals("boolean") || type.equals("java.lang.Boolean") || + type.equals("void") || type.equals("java.lang.Void") || + type.equals("java.lang.String") || + type.equals("java.util.Date") || + type.equals("java.lang.Object"); + } + + private static List generateParameterTypes(String[] parameterTypes, ServiceDefinition serviceDefinition) { + List parameters = new ArrayList<>(); + for (String type : parameterTypes) { + Object result = generateType(serviceDefinition, type); + parameters.add(result); + } + return parameters; + } + + private static TypeDefinition findTypeDefinition(ServiceDefinition serviceDefinition, String type) { + return serviceDefinition.getTypes().stream() + .filter(t -> t.getType().equals(type)) + .findFirst().orElse(new TypeDefinition(type)); + } + + private static void generateComplexType(ServiceDefinition sd, TypeDefinition td, Map holder) { + td.getProperties().forEach((name, type) -> { + if (isPrimitiveType(type)) { + holder.put(name, generatePrimitiveType(type)); + } else { + generateEnclosedType(holder, name, sd, type); + } + }); + } + + private static Object generateComplexType(ServiceDefinition sd, TypeDefinition td) { + Map holder = new HashMap<>(); + generateComplexType(sd, td, holder); + return holder; + } + + private static boolean isMap(TypeDefinition td) { + String type = StringUtils.substringBefore(td.getType(), "<"); + Matcher matcher = MAP_PATTERN.matcher(type); + return matcher.matches(); + } + + private static boolean isCollection(TypeDefinition td) { + String type = StringUtils.substringBefore(td.getType(), "<"); + Matcher matcher = COLLECTION_PATTERN.matcher(type); + return matcher.matches(); + } + + private static boolean isArray(TypeDefinition td) { + return StringUtils.endsWith(td.getType(), "[]"); + } + + private static Object generatePrimitiveType(TypeDefinition td) { + return generatePrimitiveType(td.getType()); + } + + private static Object generatePrimitiveType(String type) { + switch (type) { + case "byte": + case "java.lang.Byte": + case "short": + case "java.lang.Short": + case "int": + case "java.lang.Integer": + case "long": + case "java.lang.Long": + return 0; + case "float": + case "java.lang.Float": + case "double": + case "java.lang.Double": + return 0.0; + case "boolean": + case "java.lang.Boolean": + return true; + case "void": + case "java.lang.Void": + return null; + case "java.lang.String": + return ""; + case "java.lang.Object": + return Collections.emptyMap(); + case "java.util.Date": + return System.currentTimeMillis(); + default: + return Collections.emptyMap(); + } + } + + private static Object generateType(ServiceDefinition sd, String type) { + TypeDefinition td = findTypeDefinition(sd, type); + return generateType(sd, td); + } + + private static Object generateType(ServiceDefinition sd, TypeDefinition td) { + if (isPrimitiveType(td)) { + return generatePrimitiveType(td); + } else if (isMap(td)) { + return generateMapType(sd, td); + } else if (isArray(td)) { + return generateArrayType(sd, td); + } else if (isCollection(td)) { + return generateCollectionType(sd, td); + } else { + return generateComplexType(sd, td); + } + } + + private static Object generateMapType(ServiceDefinition sd, TypeDefinition td) { + String keyType = StringUtils.substringAfter(td.getType(), "<"); + keyType = StringUtils.substringBefore(keyType, ","); + keyType = StringUtils.strip(keyType); + + Map map = new HashMap<>(); + // 生成 key 默认值 + Object key = generateType(sd, keyType); + + // 生成 value 默认值 + String valueType = StringUtils.substringAfter(td.getType(), ","); + valueType = StringUtils.substringBefore(valueType, ">"); + valueType = StringUtils.strip(valueType); + valueType = StringUtils.isNotEmpty(valueType) ? valueType : "java.lang.Object"; + Object value = generateType(sd, valueType); + map.put(key, value); + return map; + } + + private static Object generateCollectionType(ServiceDefinition sd, TypeDefinition td) { + String type = StringUtils.substringAfter(td.getType(), "<"); + type = StringUtils.substringBefore(type, ">"); + if (StringUtils.isEmpty(type)) { + // 如果 collection 类型未声明,则生成空 collection + return new Object[]{}; + } + return new Object[]{generateType(sd, type)}; + + } + + private static Object generateArrayType(ServiceDefinition sd, TypeDefinition td) { + String type = StringUtils.substringBeforeLast(td.getType(), "[]"); + return new Object[]{generateType(sd, type)}; + } + + private static void generateEnclosedType(Map holder, String key, ServiceDefinition sd, String type) { + if (isPrimitiveType(type)) { + holder.put(key, generateType(sd, type)); + } else { + TypeDefinition td = findTypeDefinition(sd, type); + if (td.getProperties() == null || td.getProperties().size() == 0) { + holder.put(key, generateType(sd, td)); + } else { + Map enclosedMap = new HashMap<>(); + holder.put(key, enclosedMap); + generateComplexType(sd, td, enclosedMap); + } + + } + } +} diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/SyncUtils.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/SyncUtils.java index b548d9123..88e9e738c 100644 --- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/SyncUtils.java +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/common/util/SyncUtils.java @@ -18,6 +18,8 @@ import org.apache.dubbo.admin.model.domain.Consumer; import org.apache.dubbo.admin.model.domain.Provider; +import org.apache.dubbo.admin.model.domain.RegistrySource; +import org.apache.dubbo.common.BaseServiceMetadata; import org.apache.dubbo.common.URL; import java.util.ArrayList; @@ -48,7 +50,10 @@ public static Provider url2Provider(Pair pair) { Provider p = new Provider(); p.setHash(id); - p.setService(url.getServiceKey()); + String group = url.getUrlParam().getParameter(Constants.GROUP_KEY); + String version = url.getUrlParam().getParameter(Constants.VERSION_KEY); + String service = BaseServiceMetadata.buildServiceKey(url.getServiceInterface(), group, version); + p.setService(service); p.setAddress(url.getAddress()); p.setApplication(url.getParameter(Constants.APPLICATION_KEY)); p.setUrl(url.toIdentityString()); @@ -58,6 +63,7 @@ public static Provider url2Provider(Pair pair) { p.setEnabled(url.getParameter(Constants.ENABLED_KEY, true)); p.setWeight(url.getParameter(Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT)); p.setUsername(url.getParameter("owner")); + p.setRegistrySource(RegistrySource.INTERFACE); return p; } @@ -83,7 +89,10 @@ public static Consumer url2Consumer(Pair pair) { Consumer c = new Consumer(); c.setHash(id); - c.setService(url.getServiceKey()); + String group = url.getUrlParam().getParameter(Constants.GROUP_KEY); + String version = url.getUrlParam().getParameter(Constants.VERSION_KEY); + String service = BaseServiceMetadata.buildServiceKey(url.getServiceInterface(), group, version); + c.setService(service); c.setAddress(url.getHost()); c.setApplication(url.getParameter(Constants.APPLICATION_KEY)); c.setParameters(url.toParameterString()); diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java index bedd84d1f..7e357617c 100644 --- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java @@ -21,14 +21,21 @@ import org.apache.dubbo.admin.common.exception.ConfigurationException; import org.apache.dubbo.admin.common.util.Constants; import org.apache.dubbo.admin.registry.config.GovernanceConfiguration; +import org.apache.dubbo.admin.registry.mapping.ServiceMapping; +import org.apache.dubbo.admin.registry.mapping.impl.NoOpServiceMapping; import org.apache.dubbo.admin.registry.metadata.MetaDataCollector; import org.apache.dubbo.admin.registry.metadata.impl.NoOpMetadataCollector; 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.metadata.MappingListener; import org.apache.dubbo.registry.Registry; import org.apache.dubbo.registry.RegistryFactory; +import org.apache.dubbo.registry.RegistryService; +import org.apache.dubbo.registry.client.ServiceDiscovery; +import org.apache.dubbo.registry.client.ServiceDiscoveryFactory; +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; @@ -37,6 +44,7 @@ import java.util.Arrays; import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY; +import static org.apache.dubbo.registry.client.ServiceDiscoveryFactory.getExtension; @Configuration public class ConfigCenter { @@ -85,7 +93,8 @@ public class ConfigCenter { private URL registryUrl; private URL metadataUrl; - + @Autowired + private MappingListener mappingListener; /* * generate dynamic configuration client @@ -130,7 +139,7 @@ GovernanceConfiguration getDynamicConfiguration() { /* * generate registry client */ - @Bean + @Bean("dubboRegistry") @DependsOn("governanceConfiguration") Registry getRegistry() { Registry registry = null; @@ -148,7 +157,7 @@ Registry getRegistry() { /* * generate metadata client */ - @Bean + @Bean("metaDataCollector") @DependsOn("governanceConfiguration") MetaDataCollector getMetadataCollector() { MetaDataCollector metaDataCollector = new NoOpMetadataCollector(); @@ -168,6 +177,29 @@ MetaDataCollector getMetadataCollector() { return metaDataCollector; } + @Bean(destroyMethod = "destroy") + @DependsOn("dubboRegistry") + ServiceDiscovery getServiceDiscoveryRegistry() throws Exception { + URL registryURL = registryUrl.setPath(RegistryService.class.getName()); + ServiceDiscoveryFactory factory = getExtension(registryURL); + ServiceDiscovery serviceDiscovery = factory.getServiceDiscovery(registryURL); + serviceDiscovery.initialize(registryURL); + return serviceDiscovery; + } + + @Bean + @DependsOn("metaDataCollector") + ServiceMapping getServiceMapping() { + ServiceMapping serviceMapping = new NoOpServiceMapping(); + if (metadataUrl == null) { + return serviceMapping; + } + serviceMapping = ExtensionLoader.getExtensionLoader(ServiceMapping.class).getExtension(metadataUrl.getProtocol()); + serviceMapping.addMappingListener(mappingListener); + serviceMapping.init(metadataUrl); + return serviceMapping; + } + private URL formUrl(String config, String group, String nameSpace, String username, String password) { URL url = URL.valueOf(config); if (StringUtils.isEmpty(url.getParameter(Constants.GROUP_KEY)) && StringUtils.isNotEmpty(group)) { diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/MeshRouteController.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/MeshRouteController.java index 537ca0c3b..9f3136cbd 100644 --- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/MeshRouteController.java +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/MeshRouteController.java @@ -20,12 +20,13 @@ import org.apache.dubbo.admin.annotation.Authority; 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.MeshRouteDTO; import org.apache.dubbo.admin.service.MeshRouteService; +import org.apache.dubbo.admin.service.ProviderService; import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; @@ -45,9 +46,11 @@ public class MeshRouteController { private final MeshRouteService meshRouteService; - @Autowired - public MeshRouteController(MeshRouteService meshRouteService) { + private final ProviderService providerService; + + public MeshRouteController(MeshRouteService meshRouteService, ProviderService providerService) { this.meshRouteService = meshRouteService; + this.providerService = providerService; } @RequestMapping(method = RequestMethod.POST) @@ -57,7 +60,9 @@ public boolean createMeshRoute(@RequestBody MeshRouteDTO meshRoute, @PathVariabl if (StringUtils.isEmpty(app)) { throw new ParamValidationException("app is Empty!"); } - // todo check appName + if (providerService.findVersionInApplication(app).startsWith("2")) { + throw new VersionValidationException("dubbo 2.x does not support mesh route"); + } return meshRouteService.createMeshRule(meshRoute); } diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java index 4a9df1a09..bfd801a58 100644 --- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/ServiceController.java @@ -103,9 +103,16 @@ public ServiceDetailDTO serviceDetail(@PathVariable String service, @PathVariabl if (metadata != null) { try { // for dubbo version under 2.7, this metadata will represent as IP address, like 10.0.0.1. - // So the json conversion will fail. - FullServiceDefinition serviceDefinition = gson.fromJson(metadata, FullServiceDefinition.class); - serviceDetailDTO.setMetadata(serviceDefinition); + // So the json conversion will fail. + String release = providerService.findVersionInApplication(application); + // serialization compatible 2.x version + if (release.startsWith("2")) { + org.apache.dubbo.admin.model.domain.FullServiceDefinition serviceDefinition = gson.fromJson(metadata, org.apache.dubbo.admin.model.domain.FullServiceDefinition.class); + serviceDetailDTO.setMetadata(serviceDefinition); + } else { + FullServiceDefinition serviceDefinition = gson.fromJson(metadata, FullServiceDefinition.class); + serviceDetailDTO.setMetadata(serviceDefinition); + } } catch (JsonParseException e) { throw new VersionValidationException("dubbo 2.6 does not support metadata"); } @@ -122,6 +129,11 @@ public Set allServices(@PathVariable String env) { return new HashSet<>(providerService.findServices()); } + @RequestMapping(value = "/applications/instance", method = RequestMethod.GET) + public Set allInstanceServices(@PathVariable String env) { + return new HashSet<>(providerService.findInstanceApplications()); + } + @RequestMapping(value = "/applications", method = RequestMethod.GET) public Set allApplications(@PathVariable String env) { return providerService.findApplications(); diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/ServiceTestController.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/ServiceTestController.java index cea17080b..ca3ad49a1 100644 --- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/ServiceTestController.java +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/ServiceTestController.java @@ -23,6 +23,7 @@ import org.apache.dubbo.admin.annotation.Authority; import org.apache.dubbo.admin.common.util.ConvertUtil; import org.apache.dubbo.admin.common.util.ServiceTestUtil; +import org.apache.dubbo.admin.common.util.ServiceTestV3Util; import org.apache.dubbo.admin.model.domain.MethodMetadata; import org.apache.dubbo.admin.model.dto.ServiceTestDTO; import org.apache.dubbo.admin.service.ProviderService; @@ -71,13 +72,29 @@ public MethodMetadata methodDetail(@PathVariable String env, @RequestParam Strin MethodMetadata methodMetadata = null; if (metadata != null) { Gson gson = new Gson(); - FullServiceDefinition serviceDefinition = gson.fromJson(metadata, FullServiceDefinition.class); - List methods = serviceDefinition.getMethods(); - if (methods != null) { - for (MethodDefinition m : methods) { - if (ServiceTestUtil.sameMethod(m, method)) { - methodMetadata = ServiceTestUtil.generateMethodMeta(serviceDefinition, m); - break; + String release = providerService.findVersionInApplication(application); + if (release.startsWith("2.")) { + org.apache.dubbo.admin.model.domain.FullServiceDefinition serviceDefinition = gson.fromJson(metadata, + org.apache.dubbo.admin.model.domain.FullServiceDefinition.class); + List methods = serviceDefinition.getMethods(); + if (methods != null) { + for (org.apache.dubbo.admin.model.domain.MethodDefinition m : methods) { + if (ServiceTestUtil.sameMethod(m, method)) { + methodMetadata = ServiceTestUtil.generateMethodMeta(serviceDefinition, m); + break; + } + } + } + } else { + FullServiceDefinition serviceDefinition = gson.fromJson(metadata, + FullServiceDefinition.class); + List methods = serviceDefinition.getMethods(); + if (methods != null) { + for (MethodDefinition m : methods) { + if (ServiceTestV3Util.sameMethod(m, method)) { + methodMetadata = ServiceTestV3Util.generateMethodMeta(serviceDefinition, m); + break; + } } } } diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/FullServiceDefinition.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/FullServiceDefinition.java new file mode 100644 index 000000000..54dc59b11 --- /dev/null +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/FullServiceDefinition.java @@ -0,0 +1,41 @@ +/* + * 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.model.domain; + +import java.util.Map; + +/** + * copy from {@link org.apache.dubbo.metadata.definition.model.FullServiceDefinition} compatible 2.x version + */ +public class FullServiceDefinition extends ServiceDefinition { + private Map parameters; + + public Map getParameters() { + return parameters; + } + + public void setParameters(Map parameters) { + this.parameters = parameters; + } + + public String toString() { + return "FullServiceDefinition{" + + "parameters=" + parameters + + "} " + super.toString(); + } +} diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/MethodDefinition.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/MethodDefinition.java new file mode 100644 index 000000000..1c0b8fee1 --- /dev/null +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/MethodDefinition.java @@ -0,0 +1,108 @@ +/* + * 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.model.domain; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * copy from {@link org.apache.dubbo.metadata.definition.model.MethodDefinition} compatible 2.x version + */ +public class MethodDefinition { + + private String name; + private String[] parameterTypes; + private String returnType; + private List parameters; + private List annotations; + + public MethodDefinition() { + } + + public String getName() { + return this.name; + } + + public List getParameters() { + if (this.parameters == null) { + this.parameters = new ArrayList(); + } + + return this.parameters; + } + + public String[] getParameterTypes() { + return this.parameterTypes; + } + + public String getReturnType() { + return this.returnType; + } + + public void setName(String name) { + this.name = name; + } + + public void setParameters(List parameters) { + this.parameters = parameters; + } + + public void setParameterTypes(String[] parameterTypes) { + this.parameterTypes = TypeDefinition.formatTypes(parameterTypes); + } + + public void setReturnType(String returnType) { + this.returnType = TypeDefinition.formatType(returnType); + } + + public List getAnnotations() { + if (this.annotations == null) { + this.annotations = Collections.emptyList(); + } + + return this.annotations; + } + + public void setAnnotations(List annotations) { + this.annotations = annotations; + } + + public String toString() { + return "MethodDefinition [name=" + this.name + ", parameterTypes=" + Arrays.toString(this.parameterTypes) + ", returnType=" + this.returnType + "]"; + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } else if (!(o instanceof MethodDefinition)) { + return false; + } else { + MethodDefinition that = (MethodDefinition) o; + return Objects.equals(this.getName(), that.getName()) && Arrays.equals(this.getParameterTypes(), that.getParameterTypes()) && Objects.equals(this.getReturnType(), that.getReturnType()) && Objects.equals(this.getParameters(), that.getParameters()); + } + } + + public int hashCode() { + int result = Objects.hash(new Object[]{this.getName(), this.getReturnType(), this.getParameters()}); + result = 31 * result + Arrays.hashCode(this.getParameterTypes()); + return result; + } +} diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/Provider.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/Provider.java index 363872b16..2de0ad07e 100644 --- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/Provider.java +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/Provider.java @@ -60,6 +60,8 @@ public class Provider extends Entity { private List overrides; + private RegistrySource registrySource; + public Provider() { } @@ -181,6 +183,14 @@ public void setOverrides(List overrides) { this.overrides = overrides; } + public RegistrySource getRegistrySource() { + return registrySource; + } + + public void setRegistrySource(RegistrySource registrySource) { + this.registrySource = registrySource; + } + public URL toUrl() { Map serviceName2Map = ConvertUtil.serviceName2Map(getService()); /*if(!serviceName2Map.containsKey(Constants.INTERFACE_KEY)) { diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/RegistrySource.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/RegistrySource.java new file mode 100644 index 000000000..e54644c94 --- /dev/null +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/RegistrySource.java @@ -0,0 +1,26 @@ +/* + * 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.model.domain; + +public enum RegistrySource { + + INTERFACE, + + INSTANCE + +} \ No newline at end of file diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/ServiceDefinition.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/ServiceDefinition.java new file mode 100644 index 000000000..9205ac761 --- /dev/null +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/ServiceDefinition.java @@ -0,0 +1,133 @@ +/* + * 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.model.domain; + +import org.apache.dubbo.metadata.definition.util.ClassUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * copy from {@link org.apache.dubbo.metadata.definition.model.ServiceDefinition} compatible 2.x version + */ +public class ServiceDefinition { + + /** + * the canonical name of interface + * + * @see Class#getCanonicalName() + */ + private String canonicalName; + + /** + * the location of class file + * + * @see ClassUtils#getCodeSource(Class) + */ + private String codeSource; + + private List methods; + + /** + * the definitions of type + */ + private List types; + + /** + * the definitions of annotations + */ + private List annotations; + + public String getCanonicalName() { + return canonicalName; + } + + public String getCodeSource() { + return codeSource; + } + + public List getMethods() { + if (methods == null) { + methods = new ArrayList<>(); + } + return methods; + } + + public List getTypes() { + if (types == null) { + types = new ArrayList<>(); + } + return types; + } + + public String getUniqueId() { + return canonicalName + "@" + codeSource; + } + + public void setCanonicalName(String canonicalName) { + this.canonicalName = canonicalName; + } + + public void setCodeSource(String codeSource) { + this.codeSource = codeSource; + } + + public void setMethods(List methods) { + this.methods = methods; + } + + public void setTypes(List types) { + this.types = types; + } + + public List getAnnotations() { + if (annotations == null) { + annotations = Collections.emptyList(); + } + return annotations; + } + + public void setAnnotations(List annotations) { + this.annotations = annotations; + } + + public String toString() { + return "ServiceDefinition [canonicalName=" + canonicalName + ", codeSource=" + codeSource + ", methods=" + + methods + "]"; + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof ServiceDefinition)) { + return false; + } + ServiceDefinition that = (ServiceDefinition) o; + return Objects.equals(getCanonicalName(), that.getCanonicalName()) && + Objects.equals(getCodeSource(), that.getCodeSource()) && + Objects.equals(getMethods(), that.getMethods()) && + Objects.equals(getTypes(), that.getTypes()); + } + + public int hashCode() { + return Objects.hash(getCanonicalName(), getCodeSource(), getMethods(), getTypes()); + } +} diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/TypeDefinition.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/TypeDefinition.java new file mode 100644 index 000000000..71ed8fa8c --- /dev/null +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/TypeDefinition.java @@ -0,0 +1,161 @@ +/* + * 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.model.domain; + +import org.apache.dubbo.common.utils.StringUtils; + +import com.google.gson.annotations.SerializedName; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + + +/** + * copy from {@link org.apache.dubbo.metadata.definition.model.TypeDefinition} compatible 2.x version + */ +public class TypeDefinition implements Serializable { + private String id; + private String type; + @SerializedName("items") + private List items; + @SerializedName("enum") + private List enums; + private String $ref; + private Map properties; + private String typeBuilderName; + + public TypeDefinition() { + } + + public TypeDefinition(String type) { + this.setType(type); + } + + public static String[] formatTypes(String[] types) { + String[] newTypes = new String[types.length]; + + for (int i = 0; i < types.length; ++i) { + newTypes[i] = formatType(types[i]); + } + + return newTypes; + } + + public static String formatType(String type) { + return isGenericType(type) ? formatGenericType(type) : type; + } + + private static String formatGenericType(String type) { + return StringUtils.replace(type, ", ", ","); + } + + private static boolean isGenericType(String type) { + return type.contains("<") && type.contains(">"); + } + + public String get$ref() { + return this.$ref; + } + + public List getEnums() { + if (this.enums == null) { + this.enums = new ArrayList(); + } + + return this.enums; + } + + public String getId() { + return this.id; + } + + public List getItems() { + if (this.items == null) { + this.items = new ArrayList(); + } + + return this.items; + } + + public Map getProperties() { + if (this.properties == null) { + this.properties = new HashMap(); + } + + return this.properties; + } + + public String getType() { + return this.type; + } + + public String getTypeBuilderName() { + return this.typeBuilderName; + } + + public void set$ref(String $ref) { + this.$ref = $ref; + } + + public void setEnums(List enums) { + this.enums = enums; + } + + public void setId(String id) { + this.id = id; + } + + public void setItems(List items) { + this.items = items; + } + + public void setProperties(Map properties) { + this.properties = properties; + } + + public void setType(String type) { + this.type = formatType(type); + } + + public void setTypeBuilderName(String typeBuilderName) { + this.typeBuilderName = typeBuilderName; + } + + public String toString() { + return "TypeDefinition [id=" + this.id + ", type=" + this.type + ", properties=" + this.properties + ", $ref=" + this.$ref + "]"; + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } else if (!(o instanceof TypeDefinition)) { + return false; + } else { + TypeDefinition that = (TypeDefinition) o; + return Objects.equals(this.getId(), that.getId()) && Objects.equals(this.getType(), that.getType()) && Objects.equals(this.getItems(), that.getItems()) && Objects.equals(this.getEnums(), that.getEnums()) && Objects.equals(this.get$ref(), that.get$ref()) && Objects.equals(this.getProperties(), that.getProperties()); + } + } + + public int hashCode() { + return Objects.hash(new Object[]{this.getId(), this.getType(), this.getItems(), this.getEnums(), this.get$ref(), this.getProperties()}); + } +} diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDTO.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDTO.java index 0202526c2..cd1591631 100644 --- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDTO.java +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDTO.java @@ -17,15 +17,17 @@ package org.apache.dubbo.admin.model.dto; +import org.apache.dubbo.admin.model.domain.RegistrySource; import org.apache.commons.lang3.StringUtils; import java.util.Objects; -public class ServiceDTO implements Comparable{ +public class ServiceDTO implements Comparable { private String service; private String appName; private String group; private String version; + private RegistrySource registrySource; public String getService() { return service; @@ -59,6 +61,14 @@ public void setVersion(String version) { this.version = version; } + public RegistrySource getRegistrySource() { + return registrySource; + } + + public void setRegistrySource(RegistrySource registrySource) { + this.registrySource = registrySource; + } + @Override public int compareTo(ServiceDTO o) { int result = StringUtils.trimToEmpty(appName).compareTo(StringUtils.trimToEmpty(o.getAppName())); @@ -70,6 +80,9 @@ public int compareTo(ServiceDTO o) { if (result == 0) { result = StringUtils.trimToEmpty(version).compareTo(StringUtils.trimToEmpty(o.getVersion())); } + if (result == 0) { + result = registrySource.compareTo(o.registrySource); + } } return result; } @@ -84,11 +97,11 @@ public boolean equals(Object o) { } ServiceDTO that = (ServiceDTO) o; return Objects.equals(service, that.service) && Objects.equals(appName, that.appName) && Objects - .equals(group, that.group) && Objects.equals(version, that.version); + .equals(group, that.group) && Objects.equals(version, that.version) && Objects.equals(registrySource, that.registrySource); } @Override public int hashCode() { - return Objects.hash(service, appName, group, version); + return Objects.hash(service, appName, group, version, registrySource); } } diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDetailDTO.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDetailDTO.java index 1ef4bebd9..d15a7bf28 100644 --- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDetailDTO.java +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/dto/ServiceDetailDTO.java @@ -19,7 +19,6 @@ import org.apache.dubbo.admin.model.domain.Consumer; import org.apache.dubbo.admin.model.domain.Provider; -import org.apache.dubbo.metadata.definition.model.FullServiceDefinition; import java.util.List; @@ -30,7 +29,7 @@ public class ServiceDetailDTO { private String service; private String application; - FullServiceDefinition metadata; + Object metadata; public String getService() { return service; @@ -64,11 +63,11 @@ public void setConsumers(List consumers) { this.consumers = consumers; } - public FullServiceDefinition getMetadata() { + public Object getMetadata() { return metadata; } - public void setMetadata(FullServiceDefinition metadata) { + public void setMetadata(Object metadata) { this.metadata = metadata; } } diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AddressChangeListener.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AddressChangeListener.java new file mode 100644 index 000000000..076bb5680 --- /dev/null +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AddressChangeListener.java @@ -0,0 +1,32 @@ +/* + * 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.registry.mapping; + +import org.apache.dubbo.common.URL; + +import java.util.List; + +public interface AddressChangeListener { + + /** + * notify instance address url change + * @param protocolServiceKey {group}/{path/interfaceName}:{version}:protocol + * @param urls instance address url + */ + void notifyAddressChanged(String protocolServiceKey, List urls); +} diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AdminMappingListener.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AdminMappingListener.java new file mode 100644 index 000000000..56db6e375 --- /dev/null +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AdminMappingListener.java @@ -0,0 +1,131 @@ +/* + * 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.registry.mapping; + +import org.apache.dubbo.admin.common.util.Constants; +import org.apache.dubbo.admin.service.impl.InstanceRegistryCache; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.common.utils.NetUtils; +import org.apache.dubbo.metadata.MappingChangedEvent; +import org.apache.dubbo.metadata.MappingListener; +import org.apache.dubbo.registry.client.InstanceAddressURL; +import org.apache.dubbo.registry.client.ServiceDiscovery; +import org.apache.dubbo.registry.client.ServiceInstance; +import org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent; +import org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener; + +import com.google.common.collect.Sets; +import org.springframework.stereotype.Component; + +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.stream.Collectors; + +@Component +public class AdminMappingListener implements MappingListener { + + private static final URL CONSUMER_URL = new URL(Constants.ADMIN_PROTOCOL, NetUtils.getLocalHost(), 0, "", + Constants.INTERFACE_KEY, Constants.ANY_VALUE, + Constants.GROUP_KEY, Constants.ANY_VALUE, + Constants.VERSION_KEY, Constants.ANY_VALUE, + Constants.CLASSIFIER_KEY, Constants.ANY_VALUE, + Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY + "," + + Constants.CONSUMERS_CATEGORY + "," + + Constants.ROUTERS_CATEGORY + "," + + Constants.CONFIGURATORS_CATEGORY, + Constants.ENABLED_KEY, Constants.ANY_VALUE, + Constants.CHECK_KEY, String.valueOf(false)); + + /* app - listener */ + private final Map serviceListeners = new ConcurrentHashMap<>(); + + private final ServiceDiscovery serviceDiscovery; + + private final InstanceRegistryCache instanceRegistryCache; + + public AdminMappingListener(ServiceDiscovery serviceDiscovery, InstanceRegistryCache instanceRegistryCache) { + this.serviceDiscovery = serviceDiscovery; + this.instanceRegistryCache = instanceRegistryCache; + } + + @Override + public void onEvent(MappingChangedEvent event) { + Set apps = event.getApps(); + if (CollectionUtils.isEmpty(apps)) { + return; + } + for (String serviceName : apps) { + ServiceInstancesChangedListener serviceInstancesChangedListener = serviceListeners.get(serviceName); + if (serviceInstancesChangedListener == null) { + synchronized (this) { + serviceInstancesChangedListener = serviceListeners.get(serviceName); + if (serviceInstancesChangedListener == null) { + AddressChangeListener addressChangeListener = new DefaultAddressChangeListener(serviceName, instanceRegistryCache); + serviceInstancesChangedListener = new AdminServiceInstancesChangedListener(Sets.newHashSet(serviceName), serviceDiscovery, addressChangeListener); + serviceInstancesChangedListener.setUrl(CONSUMER_URL); + List serviceInstances = serviceDiscovery.getInstances(serviceName); + if (CollectionUtils.isNotEmpty(serviceInstances)) { + serviceInstancesChangedListener.onEvent(new ServiceInstancesChangedEvent(serviceName, serviceInstances)); + } + serviceListeners.put(serviceName, serviceInstancesChangedListener); + serviceInstancesChangedListener.setUrl(CONSUMER_URL); + serviceDiscovery.addServiceInstancesChangedListener(serviceInstancesChangedListener); + } + } + } + } + } + + private static class DefaultAddressChangeListener implements AddressChangeListener { + + private String serviceName; + + private InstanceRegistryCache instanceRegistryCache; + + public DefaultAddressChangeListener(String serviceName, InstanceRegistryCache instanceRegistryCache) { + this.serviceName = serviceName; + this.instanceRegistryCache = instanceRegistryCache; + } + + @Override + public void notifyAddressChanged(String protocolServiceKey, List urls) { + String serviceKey = removeProtocol(protocolServiceKey); + ConcurrentMap>> appServiceMap = instanceRegistryCache.computeIfAbsent(Constants.PROVIDERS_CATEGORY, key -> new ConcurrentHashMap<>()); + Map> serviceMap = appServiceMap.computeIfAbsent(serviceName, key -> new ConcurrentHashMap<>()); + if (CollectionUtils.isEmpty(urls)) { + serviceMap.remove(serviceKey); + } else { + List instanceAddressUrls = urls.stream().map(url -> (InstanceAddressURL) url).collect(Collectors.toList()); + serviceMap.put(serviceKey, instanceAddressUrls); + } + } + + private String removeProtocol(String protocolServiceKey) { + int index = protocolServiceKey.lastIndexOf(":"); + if (index == -1) { + return protocolServiceKey; + } + return protocolServiceKey.substring(0, index); + } + } + +} diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AdminServiceInstancesChangedListener.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AdminServiceInstancesChangedListener.java new file mode 100644 index 000000000..1afde5539 --- /dev/null +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/AdminServiceInstancesChangedListener.java @@ -0,0 +1,50 @@ +/* + * 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.registry.mapping; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.registry.client.ServiceDiscovery; +import org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class AdminServiceInstancesChangedListener extends ServiceInstancesChangedListener { + + private AddressChangeListener addressChangeListener; + + private Map oldServiceUrls; + + public AdminServiceInstancesChangedListener(Set serviceNames, ServiceDiscovery serviceDiscovery, AddressChangeListener addressChangeListener) { + super(serviceNames, serviceDiscovery); + this.addressChangeListener = addressChangeListener; + oldServiceUrls = new HashMap<>(); + } + + protected void notifyAddressChanged() { + oldServiceUrls.keySet().stream() + .filter(protocolServiceKey -> !serviceUrls.containsKey(protocolServiceKey)) + .forEach(protocolServiceKey -> addressChangeListener.notifyAddressChanged(protocolServiceKey, new ArrayList<>())); + serviceUrls.forEach((protocolServiceKey, urls) -> addressChangeListener.notifyAddressChanged(protocolServiceKey, (List) urls)); + + oldServiceUrls = serviceUrls; + } +} diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/ServiceMapping.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/ServiceMapping.java new file mode 100644 index 000000000..6559a2996 --- /dev/null +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/ServiceMapping.java @@ -0,0 +1,36 @@ +/* + * 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.registry.mapping; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.extension.SPI; +import org.apache.dubbo.metadata.MappingListener; + +/** + * listen all mapping group service + */ +@SPI("zookeeper") +public interface ServiceMapping { + + void init(URL url); + + void listenerAll(); + + void addMappingListener(MappingListener listener); + +} diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/impl/NoOpServiceMapping.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/impl/NoOpServiceMapping.java new file mode 100644 index 000000000..845efa2aa --- /dev/null +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/impl/NoOpServiceMapping.java @@ -0,0 +1,40 @@ +/* + * 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.registry.mapping.impl; + +import org.apache.dubbo.admin.registry.mapping.ServiceMapping; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.metadata.MappingListener; + +public class NoOpServiceMapping implements ServiceMapping { + + @Override + public void init(URL url) { + + } + + @Override + public void listenerAll() { + + } + + @Override + public void addMappingListener(MappingListener listener) { + + } +} diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/impl/ZookeeperServiceMapping.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/impl/ZookeeperServiceMapping.java new file mode 100644 index 000000000..799c0403d --- /dev/null +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/mapping/impl/ZookeeperServiceMapping.java @@ -0,0 +1,93 @@ +/* + * 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.registry.mapping.impl; + +import org.apache.dubbo.admin.common.util.Constants; +import org.apache.dubbo.admin.registry.mapping.ServiceMapping; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.common.utils.ConcurrentHashSet; +import org.apache.dubbo.metadata.MappingChangedEvent; +import org.apache.dubbo.metadata.MappingListener; +import org.apache.dubbo.remoting.zookeeper.ZookeeperClient; +import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter; + +import java.util.List; +import java.util.Set; + +import static org.apache.dubbo.metadata.ServiceNameMapping.getAppNames; + + +public class ZookeeperServiceMapping implements ServiceMapping { + + private ZookeeperClient zkClient; + + private final static String MAPPING_PATH = Constants.PATH_SEPARATOR + Constants.DEFAULT_ROOT + Constants.PATH_SEPARATOR + Constants.DEFAULT_MAPPING_GROUP; + + private final Set listeners = new ConcurrentHashSet<>(); + + private final Set anyServices = new ConcurrentHashSet<>(); + + @Override + public void init(URL url) { + ZookeeperTransporter zookeeperTransporter = ZookeeperTransporter.getExtension(); + zkClient = zookeeperTransporter.connect(url); + listenerAll(); + } + + @Override + public void listenerAll() { + zkClient.create(MAPPING_PATH, false); + List services = zkClient.addChildListener(MAPPING_PATH, (path, currentChildList) -> { + for (String child : currentChildList) { + if (anyServices.add(child)) { + notifyMappingChangedEvent(child); + } + } + }); + if (CollectionUtils.isNotEmpty(services)) { + for (String service : services) { + if (anyServices.add(service)) { + notifyMappingChangedEvent(service); + } + } + } + } + + private void notifyMappingChangedEvent(String service) { + if (service.equals(Constants.CONFIGURATORS_CATEGORY) || service.equals(Constants.CONSUMERS_CATEGORY) + || service.equals(Constants.PROVIDERS_CATEGORY) || service.equals(Constants.ROUTERS_CATEGORY)) { + return; + } + String servicePath = MAPPING_PATH + Constants.PATH_SEPARATOR + service; + String content = zkClient.getContent(servicePath); + if (content != null) { + Set apps = getAppNames(content); + MappingChangedEvent event = new MappingChangedEvent(service, apps); + for (MappingListener listener : listeners) { + listener.onEvent(event); + } + } + } + + @Override + public void addMappingListener(MappingListener listener) { + listeners.add(listener); + } + +} diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/ProviderService.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/ProviderService.java index 95d46f857..5417d3022 100644 --- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/ProviderService.java +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/ProviderService.java @@ -25,26 +25,11 @@ /** * ProviderService - * */ public interface ProviderService { void create(Provider provider); -// void enableProvider(String id); - -// void disableProvider(String id); - -// void doublingProvider(String id); - -// void halvingProvider(String id); - - void deleteStaticProvider(String id); - - void updateProvider(Provider provider); - - Provider findProvider(String id); - String getProviderMetaData(MetadataIdentifier providerIdentifier); /** @@ -54,18 +39,20 @@ public interface ProviderService { */ Set findServices(); + /** + * Get all instance registry provider's service name + * + * @return list of all provider's service name + */ + Set findInstanceApplications(); + + String findServiceVersion(String serviceName, String application); String findVersionInApplication(String application); List findAddresses(); - List findAddressesByApplication(String application); - - List findAddressesByService(String serviceName); - - List findApplicationsByServiceName(String serviceName); - /** * Get provider list with specific service name. * @@ -74,8 +61,6 @@ public interface ProviderService { */ List findByService(String serviceName); - List findByAppandService(String app, String serviceName); - List findAll(); /** @@ -86,8 +71,6 @@ public interface ProviderService { */ List findByAddress(String providerAddress); - List findServicesByAddress(String providerAddress); - Set findApplications(); /** @@ -100,13 +83,9 @@ public interface ProviderService { List findServicesByApplication(String application); - List findMethodsByService(String serviceName); - - Provider findByServiceAndAddress(String service, String address); - /** * Get a set of service data object. - * + *

* ServiceDTO object contains base information include * service name , application, group and version. * diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/RegistryCache.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/RegistryCache.java new file mode 100644 index 000000000..0335909e2 --- /dev/null +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/RegistryCache.java @@ -0,0 +1,48 @@ +/* + * 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 java.util.function.Function; + +/** + * cache registry url + */ +public interface RegistryCache { + + /** + * put cache + * + * @param key key + * @param value value + */ + void put(K key, V value); + + /** + * get cache + * + * @param key key + * @return value + */ + V get(K key); + + + default V computeIfAbsent(K key, Function mappingFunction) { + return null; + } + +} diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/RegistryServerSync.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/RegistryServerSync.java index f57cdb3d1..dab1a4371 100644 --- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/RegistryServerSync.java +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/RegistryServerSync.java @@ -19,6 +19,8 @@ import org.apache.dubbo.admin.common.util.CoderUtil; import org.apache.dubbo.admin.common.util.Constants; import org.apache.dubbo.admin.common.util.Tool; +import org.apache.dubbo.admin.service.impl.InterfaceRegistryCache; +import org.apache.dubbo.common.BaseServiceMetadata; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; @@ -69,13 +71,11 @@ public class RegistryServerSync implements DisposableBean, NotifyListener { * ConcurrentMap>> * registryCache */ - private final ConcurrentMap>> registryCache = new ConcurrentHashMap<>(); @Autowired private Registry registry; - public ConcurrentMap>> getRegistryCache() { - return registryCache; - } + @Autowired + private InterfaceRegistryCache interfaceRegistryCache; @EventListener(classes = ApplicationReadyEvent.class) public void startSubscribe() { @@ -98,16 +98,19 @@ public void notify(List urls) { final Map>> categories = new HashMap<>(); String interfaceName = null; for (URL url : urls) { - String category = url.getParameter(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY); + String category = url.getUrlParam().getParameter(Constants.CATEGORY_KEY); + if (category == null) { + category = Constants.PROVIDERS_CATEGORY; + } // NOTE: group and version in empty protocol is * if (Constants.EMPTY_PROTOCOL.equalsIgnoreCase(url.getProtocol())) { - ConcurrentMap> services = registryCache.get(category); + ConcurrentMap> services = interfaceRegistryCache.get(category); if (services != null) { - String group = url.getParameter(Constants.GROUP_KEY); - String version = url.getParameter(Constants.VERSION_KEY); + String group = url.getUrlParam().getParameter(Constants.GROUP_KEY); + String version = url.getUrlParam().getParameter(Constants.VERSION_KEY); // NOTE: group and version in empty protocol is * if (!Constants.ANY_VALUE.equals(group) && !Constants.ANY_VALUE.equals(version)) { - services.remove(url.getServiceKey()); + services.remove(url.getServiceInterface()); } else { for (Map.Entry> serviceEntry : services.entrySet()) { String service = serviceEntry.getKey(); @@ -128,7 +131,9 @@ public void notify(List urls) { services = new HashMap<>(); categories.put(category, services); } - String service = url.getServiceKey(); + String group = url.getUrlParam().getParameter(Constants.GROUP_KEY); + String version = url.getUrlParam().getParameter(Constants.VERSION_KEY); + String service = BaseServiceMetadata.buildServiceKey(url.getServiceInterface(), group, version); Map ids = services.get(service); if (ids == null) { ids = new HashMap<>(); @@ -150,10 +155,10 @@ public void notify(List urls) { } for (Map.Entry>> categoryEntry : categories.entrySet()) { String category = categoryEntry.getKey(); - ConcurrentMap> services = registryCache.get(category); + ConcurrentMap> services = interfaceRegistryCache.get(category); if (services == null) { services = new ConcurrentHashMap>(); - registryCache.put(category, services); + interfaceRegistryCache.put(category, services); } else {// Fix map can not be cleared when service is unregistered: when a unique “group/service:version” service is unregistered, but we still have the same services with different version or group, so empty protocols can not be invoked. Set keys = new HashSet(services.keySet()); for (String key : keys) { diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/AbstractService.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/AbstractService.java index f7bae0d49..501b13eca 100644 --- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/AbstractService.java +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/AbstractService.java @@ -18,7 +18,6 @@ import org.apache.dubbo.admin.registry.config.GovernanceConfiguration; import org.apache.dubbo.admin.registry.metadata.MetaDataCollector; -import org.apache.dubbo.admin.service.RegistryServerSync; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; @@ -42,10 +41,10 @@ public class AbstractService { protected MetaDataCollector metaDataCollector; @Autowired - private RegistryServerSync sync; + private InterfaceRegistryCache interfaceRegistryCache; - public ConcurrentMap>> getRegistryCache() { - return sync.getRegistryCache(); + public ConcurrentMap>> getInterfaceRegistryCache() { + return interfaceRegistryCache.getRegistryCache(); } } diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ConsumerServiceImpl.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ConsumerServiceImpl.java index 4a803ed63..0d0f2e595 100644 --- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ConsumerServiceImpl.java +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ConsumerServiceImpl.java @@ -52,7 +52,7 @@ public String getConsumerMetadata(MetadataIdentifier consumerIdentifier) { private Map findAllConsumerUrl() { Map filter = new HashMap(); filter.put(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY); - return SyncUtils.filterFromCategory(getRegistryCache(), filter); + return SyncUtils.filterFromCategory(getInterfaceRegistryCache(), filter); } @@ -69,7 +69,7 @@ private Map findConsumerUrlByAddress(String address) { filter.put(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY); filter.put(SyncUtils.ADDRESS_FILTER_KEY, address); - return SyncUtils.filterFromCategory(getRegistryCache(), filter); + return SyncUtils.filterFromCategory(getInterfaceRegistryCache(), filter); } public Map findConsumerUrlByService(String service) { @@ -77,7 +77,7 @@ public Map findConsumerUrlByService(String service) { filter.put(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY); filter.put(SyncUtils.SERVICE_FILTER_KEY, service); - return SyncUtils.filterFromCategory(getRegistryCache(), filter); + return SyncUtils.filterFromCategory(getInterfaceRegistryCache(), filter); } @Override @@ -85,7 +85,7 @@ public String findVersionInApplication(String application) { Map filter = new HashMap<>(); filter.put(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY); filter.put(Constants.APPLICATION_KEY, application); - Map stringURLMap = SyncUtils.filterFromCategory(getRegistryCache(), filter); + Map stringURLMap = SyncUtils.filterFromCategory(getInterfaceRegistryCache(), filter); if (stringURLMap == null || stringURLMap.isEmpty()) { throw new ParamValidationException("there is no consumer for application: " + application); } diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InstanceRegistryCache.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InstanceRegistryCache.java new file mode 100644 index 000000000..9f1b5acaa --- /dev/null +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InstanceRegistryCache.java @@ -0,0 +1,55 @@ +/* + * 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.impl; + +import org.apache.dubbo.admin.service.RegistryCache; +import org.apache.dubbo.registry.client.InstanceAddressURL; + +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.function.Function; + +/** + * instance registry url {@link InstanceAddressURL} cache + * key --> category,value --> ConcurrentMap>> + */ +@Component +public class InstanceRegistryCache implements RegistryCache>>> { + + private final ConcurrentMap>>> registryCache = new ConcurrentHashMap<>(); + + @Override + public void put(String key, ConcurrentMap>> value) { + registryCache.put(key, value); + } + + @Override + public ConcurrentMap>> get(String key) { + return registryCache.get(key); + } + + @Override + public ConcurrentMap>> computeIfAbsent(String key, + Function>>> mappingFunction) { + return registryCache.computeIfAbsent(key, mappingFunction); + } +} diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InstanceRegistryQueryHelper.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InstanceRegistryQueryHelper.java new file mode 100644 index 000000000..6391d4c88 --- /dev/null +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InstanceRegistryQueryHelper.java @@ -0,0 +1,156 @@ +/* + * 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.impl; + +import org.apache.dubbo.admin.common.util.Constants; +import org.apache.dubbo.admin.model.domain.Provider; +import org.apache.dubbo.admin.model.domain.RegistrySource; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.metadata.MetadataInfo; +import org.apache.dubbo.registry.client.InstanceAddressURL; +import org.apache.dubbo.registry.client.ServiceInstance; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentMap; +import java.util.stream.Collectors; + +@Component +public class InstanceRegistryQueryHelper { + + private final InstanceRegistryCache instanceRegistryCache; + + public InstanceRegistryQueryHelper(InstanceRegistryCache instanceRegistryCache) { + this.instanceRegistryCache = instanceRegistryCache; + } + + + public Set findServices() { + Set services = Sets.newHashSet(); + ConcurrentMap>> appInterfaceMap = instanceRegistryCache.get(Constants.PROVIDERS_CATEGORY); + if (appInterfaceMap == null) { + return services; + } + appInterfaceMap.values().forEach(serviceUrlMap -> + serviceUrlMap.forEach((service, urls) -> { + if (CollectionUtils.isNotEmpty(urls)) { + services.add(service); + } + })); + return services; + } + + public Set findApplications() { + ConcurrentMap>> appInterfaceMap = instanceRegistryCache.get(Constants.PROVIDERS_CATEGORY); + if (appInterfaceMap == null) { + return Sets.newHashSet(); + } + return Sets.newHashSet(appInterfaceMap.keySet()); + } + + public List findByService(String serviceName) { + ConcurrentMap>> appInterfaceMap = instanceRegistryCache.get(Constants.PROVIDERS_CATEGORY); + if (appInterfaceMap == null) { + return Lists.newArrayList(); + } + List providerUrls = Lists.newArrayList(); + appInterfaceMap.values().forEach(serviceUrlMap -> + serviceUrlMap.forEach((service, urls) -> { + if (CollectionUtils.isNotEmpty(urls) && service.equals(serviceName)) { + providerUrls.addAll(urls); + } + })); + return urlsToProviderList(providerUrls).stream() + .filter(provider -> provider.getService().equals(serviceName)) + .collect(Collectors.toList()); + } + + public List findByAddress(String providerAddress) { + ConcurrentMap>> appInterfaceMap = instanceRegistryCache.get(Constants.PROVIDERS_CATEGORY); + if (appInterfaceMap == null) { + return Lists.newArrayList(); + } + List providerUrls = Lists.newArrayList(); + appInterfaceMap.values().forEach(serviceUrlMap -> + serviceUrlMap.forEach((service, urls) -> { + if (CollectionUtils.isNotEmpty(urls)) { + urls.forEach(url -> { + if ((url.getInstance().getHost().equals(providerAddress))) { + providerUrls.add(url); + } + }); + } + })); + return urlsToProviderList(providerUrls); + } + + public List findByApplication(String application) { + ConcurrentMap>> appInterfaceMap = instanceRegistryCache.get(Constants.PROVIDERS_CATEGORY); + if (appInterfaceMap == null || appInterfaceMap.get(application) == null) { + return Lists.newArrayList(); + } + List providerUrls = Lists.newArrayList(); + appInterfaceMap.get(application).forEach((service, urls) -> providerUrls.addAll(urls)); + return urlsToProviderList(providerUrls); + } + + public String findVersionInApplication(String application) { + ConcurrentMap>> appInterfaceMap = instanceRegistryCache.get(Constants.PROVIDERS_CATEGORY); + if (appInterfaceMap == null || appInterfaceMap.get(application) == null) { + return null; + } + Map> urlsMap = appInterfaceMap.get(application); + for (Map.Entry> entry : urlsMap.entrySet()) { + List urls = entry.getValue(); + if (CollectionUtils.isNotEmpty(urls)) { + return urls.get(0).getParameter(Constants.SPECIFICATION_VERSION_KEY, "3.0.0"); + } + } + return null; + } + + private List urlsToProviderList(List urls) { + List providers = Lists.newArrayList(); + urls.stream().distinct().forEach(url -> { + ServiceInstance instance = url.getInstance(); + MetadataInfo metadataInfo = url.getMetadataInfo(); + + metadataInfo.getServices().forEach((serviceKey, serviceInfo) -> { + Provider p = new Provider(); + String service = serviceInfo.getServiceKey(); + p.setService(service); + p.setAddress(url.getAddress()); + p.setApplication(instance.getServiceName()); + p.setUrl(url.toParameterString()); + p.setDynamic(url.getParameter("dynamic", true)); + p.setEnabled(url.getParameter(Constants.ENABLED_KEY, true)); + p.setWeight(url.getParameter(Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT)); + p.setUsername(url.getParameter("owner")); + p.setRegistrySource(RegistrySource.INSTANCE); + providers.add(p); + }); + }); + return providers; + } +} diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InterfaceRegistryCache.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InterfaceRegistryCache.java new file mode 100644 index 000000000..ab5b3be48 --- /dev/null +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/InterfaceRegistryCache.java @@ -0,0 +1,51 @@ +/* + * 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.impl; + +import org.apache.dubbo.admin.service.RegistryCache; +import org.apache.dubbo.common.URL; + +import org.springframework.stereotype.Component; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * interface registry url cache + * key --> category,value --> ConcurrentMap> + */ +@Component +public class InterfaceRegistryCache implements RegistryCache>> { + + private final ConcurrentMap>> registryCache = new ConcurrentHashMap<>(); + + @Override + public void put(String key, ConcurrentMap> value) { + registryCache.put(key, value); + } + + @Override + public ConcurrentMap> get(String key) { + return registryCache.get(key); + } + + public ConcurrentMap>> getRegistryCache() { + return registryCache; + } +} diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java index 0d8308153..1defce765 100644 --- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java +++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/ProviderServiceImpl.java @@ -18,16 +18,14 @@ 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; import org.apache.dubbo.admin.common.util.Tool; import org.apache.dubbo.admin.model.domain.Provider; 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.common.URL; import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -37,7 +35,6 @@ 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; @@ -49,7 +46,7 @@ public class ProviderServiceImpl extends AbstractService implements ProviderService { @Autowired - OverrideService overrideService; + private InstanceRegistryQueryHelper instanceRegistryQueryHelper; @Override public void create(Provider provider) { @@ -63,57 +60,27 @@ public String getProviderMetaData(MetadataIdentifier providerIdentifier) { return metaDataCollector.getProviderMetaData(providerIdentifier); } - - @Override - public void deleteStaticProvider(String id) { - URL oldProvider = findProviderUrl(id); - if (oldProvider == null) { - throw new IllegalStateException("Provider was changed!"); - } - registry.unregister(oldProvider); - } - - @Override - public void updateProvider(Provider provider) { - String hash = provider.getHash(); - if (hash == null) { - throw new IllegalStateException("no provider id"); - } - - URL oldProvider = findProviderUrl(hash); - if (oldProvider == null) { - throw new IllegalStateException("Provider was changed!"); - } - URL newProvider = provider.toUrl(); - - registry.unregister(oldProvider); - registry.register(newProvider); - } - - @Override - public Provider findProvider(String id) { - return SyncUtils.url2Provider(findProviderUrlPair(id)); - } - - public Pair findProviderUrlPair(String id) { - return SyncUtils.filterFromCategory(getRegistryCache(), Constants.PROVIDERS_CATEGORY, id); - } - @Override public Set findServices() { Set ret = new HashSet<>(); - ConcurrentMap> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY); - if (providerUrls != null){ + ConcurrentMap> providerUrls = getInterfaceRegistryCache().get(Constants.PROVIDERS_CATEGORY); + if (providerUrls != null) { ret.addAll(providerUrls.keySet()); } + ret.addAll(instanceRegistryQueryHelper.findServices()); return ret; } + @Override + public Set findInstanceApplications() { + return instanceRegistryQueryHelper.findApplications(); + } + @Override public List findAddresses() { List ret = new ArrayList(); - ConcurrentMap> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY); + ConcurrentMap> providerUrls = getInterfaceRegistryCache().get(Constants.PROVIDERS_CATEGORY); if (null == providerUrls) { return ret; } @@ -128,80 +95,15 @@ public List findAddresses() { } } } - - return ret; - } - - @Override - public List findAddressesByApplication(String application) { - List ret = new ArrayList(); - ConcurrentMap> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY); - for (Map.Entry> e1 : providerUrls.entrySet()) { - Map value = e1.getValue(); - for (Map.Entry e2 : value.entrySet()) { - URL u = e2.getValue(); - if (application.equals(u.getParameter(Constants.APPLICATION))) { - String addr = u.getAddress(); - if (addr != null) { - ret.add(addr); - } - } - } - } - - return ret; - } - - @Override - public List findAddressesByService(String service) { - List ret = new ArrayList(); - ConcurrentMap> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY); - if (null == providerUrls) { - return ret; - } - - for (Map.Entry e2 : providerUrls.get(service).entrySet()) { - URL u = e2.getValue(); - String app = u.getAddress(); - if (app != null) { - ret.add(app); - } - } - - return ret; - } - - @Override - public List findApplicationsByServiceName(String service) { - List ret = new ArrayList(); - ConcurrentMap> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY); - if (null == providerUrls) { - return ret; - } - - Map value = providerUrls.get(service); - if (value == null) { - return ret; - } - for (Map.Entry e2 : value.entrySet()) { - URL u = e2.getValue(); - String app = u.getParameter(Constants.APPLICATION); - if (app != null){ - ret.add(app); - } - } - return ret; } @Override public List findByService(String serviceName) { - return SyncUtils.url2ProviderList(findProviderUrlByService(serviceName)); - } - - @Override - public List findByAppandService(String app, String serviceName) { - return SyncUtils.url2ProviderList(findProviderUrlByAppandService(app, serviceName)); + List instanceProviders = instanceRegistryQueryHelper.findByService(serviceName); + List interfaceProviders = SyncUtils.url2ProviderList(findProviderUrlByService(serviceName)); + instanceProviders.addAll(interfaceProviders); + return instanceProviders; } private Map findProviderUrlByService(String service) { @@ -209,7 +111,7 @@ private Map findProviderUrlByService(String service) { filter.put(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY); filter.put(SyncUtils.SERVICE_FILTER_KEY, service); - return SyncUtils.filterFromCategory(getRegistryCache(), filter); + return SyncUtils.filterFromCategory(getInterfaceRegistryCache(), filter); } @Override @@ -220,12 +122,15 @@ public List findAll() { private Map findAllProviderUrl() { Map filter = new HashMap(); filter.put(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY); - return SyncUtils.filterFromCategory(getRegistryCache(), filter); + return SyncUtils.filterFromCategory(getInterfaceRegistryCache(), filter); } @Override public List findByAddress(String providerAddress) { - return SyncUtils.url2ProviderList(findProviderUrlByAddress(providerAddress)); + List instanceProviders = instanceRegistryQueryHelper.findByAddress(providerAddress); + List interfaceProviders = SyncUtils.url2ProviderList(findProviderUrlByAddress(providerAddress)); + instanceProviders.addAll(interfaceProviders); + return instanceProviders; } public Map findProviderUrlByAddress(String address) { @@ -233,37 +138,14 @@ public Map findProviderUrlByAddress(String address) { filter.put(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY); filter.put(SyncUtils.ADDRESS_FILTER_KEY, address); - return SyncUtils.filterFromCategory(getRegistryCache(), filter); - } - - @Override - public List findServicesByAddress(String address) { - List ret = new ArrayList(); - - ConcurrentMap> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY); - if (providerUrls == null || address == null || address.length() == 0) { - return ret; - } - - for (Map.Entry> e1 : providerUrls.entrySet()) { - Map value = e1.getValue(); - for (Map.Entry e2 : value.entrySet()) { - URL u = e2.getValue(); - if (address.equals(u.getAddress())) { - ret.add(e1.getKey()); - break; - } - } - } - - return ret; + return SyncUtils.filterFromCategory(getInterfaceRegistryCache(), filter); } @Override public Set findApplications() { - Set ret = new HashSet<>(); - ConcurrentMap> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY); - if (providerUrls == null){ + Set ret = instanceRegistryQueryHelper.findApplications(); + ConcurrentMap> providerUrls = getInterfaceRegistryCache().get(Constants.PROVIDERS_CATEGORY); + if (providerUrls == null) { return ret; } @@ -283,11 +165,18 @@ public Set findApplications() { @Override public List findByApplication(String application) { - return SyncUtils.url2ProviderList(findProviderUrlByApplication(application)); + List instanceProviders = instanceRegistryQueryHelper.findByApplication(application); + List interfaceProviders = SyncUtils.url2ProviderList(findProviderUrlByApplication(application)); + instanceProviders.addAll(interfaceProviders); + return instanceProviders; } @Override public String findVersionInApplication(String application) { + String version = instanceRegistryQueryHelper.findVersionInApplication(application); + if (StringUtils.isNotBlank(version)){ + return version; + } List services = findServicesByApplication(application); if (services == null || services.size() == 0) { throw new ParamValidationException("there is no service for application: " + application); @@ -313,23 +202,22 @@ private Map findProviderUrlByAppandService(String app, String servi filter.put(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY); filter.put(Constants.APPLICATION, app); filter.put(SyncUtils.SERVICE_FILTER_KEY, service); - return SyncUtils.filterFromCategory(getRegistryCache(), filter); + return SyncUtils.filterFromCategory(getInterfaceRegistryCache(), filter); } - private Map findProviderUrlByApplication(String application) { Map filter = new HashMap<>(); filter.put(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY); filter.put(Constants.APPLICATION, application); - return SyncUtils.filterFromCategory(getRegistryCache(), filter); + return SyncUtils.filterFromCategory(getInterfaceRegistryCache(), filter); } @Override public List findServicesByApplication(String application) { List ret = new ArrayList(); - ConcurrentMap> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY); + ConcurrentMap> providerUrls = getInterfaceRegistryCache().get(Constants.PROVIDERS_CATEGORY); if (providerUrls == null || application == null || application.length() == 0) { return ret; } @@ -348,59 +236,6 @@ public List findServicesByApplication(String application) { return ret; } - @Override - public List findMethodsByService(String service) { - List ret = new ArrayList(); - - ConcurrentMap> providerUrls = getRegistryCache().get(Constants.PROVIDERS_CATEGORY); - if (providerUrls == null || service == null || service.length() == 0){ - return ret; - } - - Map providers = providerUrls.get(service); - if (null == providers || providers.isEmpty()) { - return ret; - } - - Entry p = providers.entrySet().iterator().next(); - String value = p.getValue().getParameter("methods"); - if (value == null || value.length() == 0) { - return ret; - } - String[] methods = value.split(ParseUtils.METHOD_SPLIT); - if (methods == null || methods.length == 0) { - return ret; - } - - for (String m : methods) { - ret.add(m); - } - return ret; - } - - private URL findProviderUrl(String id) { - return findProvider(id).toUrl(); - } - - @Override - public Provider findByServiceAndAddress(String service, String address) { - return SyncUtils.url2Provider(findProviderUrl(service, address)); - } - - private Pair findProviderUrl(String service, String address) { - Map filter = new HashMap(); - filter.put(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY); - filter.put(SyncUtils.ADDRESS_FILTER_KEY, address); - - Map ret = SyncUtils.filterFromCategory(getRegistryCache(), filter); - if (ret.isEmpty()) { - return null; - } else { - String key = ret.entrySet().iterator().next().getKey(); - return new Pair(key, ret.get(key)); - } - } - @Override public Set getServiceDTOS(String pattern, String filter, String env) { List providers = new ArrayList<>(); @@ -420,15 +255,14 @@ public Set getServiceDTOS(String pattern, String filter, String env) candidates = findServices(); } else if (Constants.APPLICATION.equals(pattern)) { candidates = findApplications(); - } - else if (Constants.IP.equals(pattern)) { + } else if (Constants.IP.equals(pattern)) { candidates = findAddresses().stream().collect(Collectors.toSet()); } // replace dot symbol and asterisk symbol to java-based regex pattern filter = filter.toLowerCase().replace(Constants.PUNCTUATION_POINT, Constants.PUNCTUATION_SEPARATOR_POINT); // filter start with [* 、? 、+] will triggering PatternSyntaxException if (filter.startsWith(Constants.ANY_VALUE) - || filter.startsWith(Constants.INTERROGATION_POINT) || filter.startsWith(Constants.PLUS_SIGNS)) { + || filter.startsWith(Constants.INTERROGATION_POINT) || filter.startsWith(Constants.PLUS_SIGNS)) { filter = Constants.PUNCTUATION_POINT + filter; } // search with no case insensitive @@ -438,19 +272,16 @@ else if (Constants.IP.equals(pattern)) { if (matcher.matches() || matcher.lookingAt()) { if (Constants.SERVICE.equals(pattern)) { providers.addAll(findByService(candidate)); - } - else if (Constants.IP.equals(pattern)) { + } else if (Constants.IP.equals(pattern)) { providers.addAll(findByAddress(candidate)); - } - else { + } else { providers.addAll(findByApplication(candidate)); } } } } - Set result = convertProviders2DTO(providers); - return result; + return convertProviders2DTO(providers); } /** @@ -472,6 +303,7 @@ public Set convertProviders2DTO(List providers) { s.setService(interfaze); s.setGroup(group); s.setVersion(version); + s.setRegistrySource(provider.getRegistrySource()); result.add(s); } return result; diff --git a/dubbo-admin-server/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.admin.registry.mapping.ServiceMapping b/dubbo-admin-server/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.admin.registry.mapping.ServiceMapping new file mode 100644 index 000000000..83709e762 --- /dev/null +++ b/dubbo-admin-server/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.admin.registry.mapping.ServiceMapping @@ -0,0 +1 @@ +zookeeper=org.apache.dubbo.admin.registry.mapping.impl.ZookeeperServiceMapping \ No newline at end of file diff --git a/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/service/RegistryServerSyncTest.java b/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/service/RegistryServerSyncTest.java index a8ecc7cc1..1be485d1d 100644 --- a/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/service/RegistryServerSyncTest.java +++ b/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/service/RegistryServerSyncTest.java @@ -18,16 +18,22 @@ package org.apache.dubbo.admin.service; import org.apache.dubbo.admin.common.util.Constants; +import org.apache.dubbo.admin.service.impl.InterfaceRegistryCache; import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.url.component.URLParam; import org.apache.dubbo.registry.Registry; + +import org.junit.Before; 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 org.springframework.test.util.ReflectionTestUtils; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentMap; @@ -46,9 +52,11 @@ public class RegistryServerSyncTest { @InjectMocks private RegistryServerSync registryServerSync; - @Test - public void testGetRegistryCache() { - registryServerSync.getRegistryCache(); + private InterfaceRegistryCache interfaceRegistryCache = new InterfaceRegistryCache(); + + @Before + public void setUp() throws Exception { + ReflectionTestUtils.setField(registryServerSync, "interfaceRegistryCache", interfaceRegistryCache); } @Test @@ -71,27 +79,32 @@ public void testNotify() { // 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(Constants.CONSUMER_PROTOCOL); + HashMap consumerUrlParam = new HashMap<>(); + consumerUrlParam.put(Constants.CATEGORY_KEY,Constants.CONSUMER_PROTOCOL); + HashMap providerUrlParam = new HashMap<>(); + providerUrlParam.put(Constants.CATEGORY_KEY,Constants.PROVIDER_PROTOCOL); + when(consumerUrl.getUrlParam()).thenReturn(URLParam.parse(consumerUrlParam)); 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.getUrlParam()).thenReturn(URLParam.parse(providerUrlParam)); when(providerUrl.getParameter(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY)).thenReturn(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> consumerMap = registryServerSync.getRegistryCache().get(Constants.CONSUMER_PROTOCOL); + ConcurrentMap> consumerMap = interfaceRegistryCache.get(Constants.CONSUMER_PROTOCOL); assertTrue(consumerMap.keySet().contains("org.apache.dubbo.consumer")); - ConcurrentMap> providerMap = registryServerSync.getRegistryCache().get(Constants.PROVIDER_PROTOCOL); + ConcurrentMap> providerMap = interfaceRegistryCache.get(Constants.PROVIDER_PROTOCOL); assertTrue(providerMap.keySet().contains("org.apache.dubbo.provider")); // when url.getProtocol is empty protocol when(consumerUrl.getProtocol()).thenReturn(Constants.EMPTY_PROTOCOL); - when(consumerUrl.getParameter(Constants.GROUP_KEY)).thenReturn("dubbo"); - when(consumerUrl.getParameter(Constants.VERSION_KEY)).thenReturn("2.7.0"); + consumerUrlParam = new HashMap<>(); + consumerUrlParam.put(Constants.CATEGORY_KEY,Constants.CONSUMER_PROTOCOL); + consumerUrlParam.put(Constants.GROUP_KEY,"dubbo"); + consumerUrlParam.put(Constants.VERSION_KEY,"2.7.0"); + when(consumerUrl.getUrlParam()).thenReturn(URLParam.parse(consumerUrlParam)); registryServerSync.notify(Collections.singletonList(consumerUrl)); assertTrue(!consumerMap.keySet().contains("org.apache.dubbo.consumer")); diff --git a/dubbo-admin-ui/src/components/ServiceDetail.vue b/dubbo-admin-ui/src/components/ServiceDetail.vue index 366b5ffcd..79fa779f8 100644 --- a/dubbo-admin-ui/src/components/ServiceDetail.vue +++ b/dubbo-admin-ui/src/components/ServiceDetail.vue @@ -54,6 +54,7 @@