From 96706277243ab7d0d3c4ff0147b00c82cdc8f31b Mon Sep 17 00:00:00 2001 From: brotherlu-xcq <1285823170@qq.com> Date: Wed, 18 Aug 2021 10:00:54 +0800 Subject: [PATCH] [FOR #6301] [TASK 1] Integrate this workflow to Nacos 2.0, replace the Selector in 1.x. (#6680) * [ISSUE #6301] replace the Selector in 1.x. * [ISSUE #6301] remove the annotation of API(get all selector types). --- .../selector/AbstractCmdbSelector.java | 33 +- .../api/{naming => }/selector/Selector.java | 10 +- .../selector/context/CmdbContext.java | 5 +- .../context/SelectorContextBuilder.java | 10 +- .../naming/controllers/ServiceController.java | 50 ++- .../controllers/UpgradeOpsController.java | 40 ++- .../core/InstanceOperatorServiceImpl.java | 10 +- .../alibaba/nacos/naming/core/Service.java | 4 +- .../core/v2/metadata/ServiceMetadata.java | 4 +- .../naming/selector/CmdbLabelSelector.java | 131 ------- .../nacos/naming/selector/LabelSelector.java | 330 +++++------------- .../nacos/naming/selector/NoneSelector.java | 60 ++-- .../naming/selector/SelectorManager.java | 24 +- .../context/CmdbSelectorContextBuilder.java | 4 +- .../context/NoneSelectorContextBuilder.java | 45 +++ .../interpreter/ExpressionInterpreter.java | 194 ++++++++++ .../naming/selector/v1/LabelSelector.java | 292 ++++++++++++++++ .../naming/selector/v1/NoneSelector.java | 48 +++ .../naming/selector/{ => v1}/Selector.java | 23 +- ...> com.alibaba.nacos.api.selector.Selector} | 3 +- ...i.selector.context.SelectorContextBuilder} | 3 +- .../core/v2/metadata/ServiceMetadataTest.java | 2 +- .../selector/CmdbLabelSelectorTest.java | 51 --- .../naming/selector/LabelSelectorTest.java | 59 ++-- .../selector/MockCmdbContextBuilder.java | 4 +- .../nacos/naming/selector/MockSelector.java | 11 +- .../naming/selector/SelectorManagerTest.java | 7 +- .../naming/selector/v1/LabelSelectorTest.java | 43 +++ ...> com.alibaba.nacos.api.selector.Selector} | 0 ...i.selector.context.SelectorContextBuilder} | 0 30 files changed, 925 insertions(+), 575 deletions(-) rename api/src/main/java/com/alibaba/nacos/api/{naming => }/selector/AbstractCmdbSelector.java (64%) rename api/src/main/java/com/alibaba/nacos/api/{naming => }/selector/Selector.java (88%) rename api/src/main/java/com/alibaba/nacos/api/{naming => }/selector/context/CmdbContext.java (94%) rename api/src/main/java/com/alibaba/nacos/api/{naming => }/selector/context/SelectorContextBuilder.java (78%) delete mode 100644 naming/src/main/java/com/alibaba/nacos/naming/selector/CmdbLabelSelector.java create mode 100644 naming/src/main/java/com/alibaba/nacos/naming/selector/context/NoneSelectorContextBuilder.java create mode 100644 naming/src/main/java/com/alibaba/nacos/naming/selector/interpreter/ExpressionInterpreter.java create mode 100644 naming/src/main/java/com/alibaba/nacos/naming/selector/v1/LabelSelector.java create mode 100644 naming/src/main/java/com/alibaba/nacos/naming/selector/v1/NoneSelector.java rename naming/src/main/java/com/alibaba/nacos/naming/selector/{ => v1}/Selector.java (69%) rename naming/src/main/resources/META-INF/services/{com.alibaba.nacos.api.naming.selector.Selector => com.alibaba.nacos.api.selector.Selector} (86%) rename naming/src/main/resources/META-INF/services/{com.alibaba.nacos.api.naming.selector.context.SelectorContextBuilder => com.alibaba.nacos.api.selector.context.SelectorContextBuilder} (90%) delete mode 100644 naming/src/test/java/com/alibaba/nacos/naming/selector/CmdbLabelSelectorTest.java create mode 100644 naming/src/test/java/com/alibaba/nacos/naming/selector/v1/LabelSelectorTest.java rename naming/src/test/resources/META-INF/services/{com.alibaba.nacos.api.naming.selector.Selector => com.alibaba.nacos.api.selector.Selector} (100%) rename naming/src/test/resources/META-INF/services/{com.alibaba.nacos.api.naming.selector.context.SelectorContextBuilder => com.alibaba.nacos.api.selector.context.SelectorContextBuilder} (100%) diff --git a/api/src/main/java/com/alibaba/nacos/api/naming/selector/AbstractCmdbSelector.java b/api/src/main/java/com/alibaba/nacos/api/selector/AbstractCmdbSelector.java similarity index 64% rename from api/src/main/java/com/alibaba/nacos/api/naming/selector/AbstractCmdbSelector.java rename to api/src/main/java/com/alibaba/nacos/api/selector/AbstractCmdbSelector.java index 294ae4031..75dcbb0e9 100644 --- a/api/src/main/java/com/alibaba/nacos/api/naming/selector/AbstractCmdbSelector.java +++ b/api/src/main/java/com/alibaba/nacos/api/selector/AbstractCmdbSelector.java @@ -15,10 +15,11 @@ * */ -package com.alibaba.nacos.api.naming.selector; +package com.alibaba.nacos.api.selector; +import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.naming.pojo.Instance; -import com.alibaba.nacos.api.naming.selector.context.CmdbContext; +import com.alibaba.nacos.api.selector.context.CmdbContext; import java.util.List; @@ -33,6 +34,34 @@ import static com.alibaba.nacos.api.common.Constants.Naming.CMDB_CONTEXT_TYPE; */ public abstract class AbstractCmdbSelector implements Selector, CmdbContext, String> { + /** + * the labels expression. + */ + protected String expression; + + public String getExpression() { + return expression; + } + + public void setExpression(String expression) { + this.expression = expression; + } + + @Override + public Selector, CmdbContext, String> parse(String expression) throws NacosException { + this.expression = expression; + doParse(expression); + return this; + } + + /** + * The real parse logic implement by sub class. + * + * @param expression expression. + * @throws NacosException parse failed exception. + */ + protected abstract void doParse(String expression) throws NacosException; + @Override public List select(CmdbContext context) { return doSelect(context); diff --git a/api/src/main/java/com/alibaba/nacos/api/naming/selector/Selector.java b/api/src/main/java/com/alibaba/nacos/api/selector/Selector.java similarity index 88% rename from api/src/main/java/com/alibaba/nacos/api/naming/selector/Selector.java rename to api/src/main/java/com/alibaba/nacos/api/selector/Selector.java index fc2dcd1d2..36c0f8ff5 100644 --- a/api/src/main/java/com/alibaba/nacos/api/naming/selector/Selector.java +++ b/api/src/main/java/com/alibaba/nacos/api/selector/Selector.java @@ -15,7 +15,7 @@ * */ -package com.alibaba.nacos.api.naming.selector; +package com.alibaba.nacos.api.selector; import com.alibaba.nacos.api.exception.NacosException; import com.fasterxml.jackson.annotation.JsonTypeInfo; @@ -36,17 +36,17 @@ import java.io.Serializable; * @author chenglu * @date 2021-07-09 21:24 */ -@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION, property = "type") -public interface Selector extends Serializable { +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type") +public interface Selector extends Serializable { /** * parse the selector, build the inner info which used by {@link #select(Object)}. * - * @param condition condition. + * @param expression expression. * @return selector. * @throws NacosException parse failed exception. */ - Selector parse(D condition) throws NacosException; + Selector parse(E expression) throws NacosException; /** * select the target result. diff --git a/api/src/main/java/com/alibaba/nacos/api/naming/selector/context/CmdbContext.java b/api/src/main/java/com/alibaba/nacos/api/selector/context/CmdbContext.java similarity index 94% rename from api/src/main/java/com/alibaba/nacos/api/naming/selector/context/CmdbContext.java rename to api/src/main/java/com/alibaba/nacos/api/selector/context/CmdbContext.java index ecbf90a7a..a818723e0 100644 --- a/api/src/main/java/com/alibaba/nacos/api/naming/selector/context/CmdbContext.java +++ b/api/src/main/java/com/alibaba/nacos/api/selector/context/CmdbContext.java @@ -15,16 +15,17 @@ * */ -package com.alibaba.nacos.api.naming.selector.context; +package com.alibaba.nacos.api.selector.context; import com.alibaba.nacos.api.cmdb.pojo.Entity; import com.alibaba.nacos.api.naming.pojo.Instance; +import com.alibaba.nacos.api.selector.Selector; import java.util.List; /** * The CMDB context is given by the {@link SelectorContextBuilder#build(Object, Object)} and used for the - * {@link com.alibaba.nacos.api.naming.selector.Selector#select(Object)}. + * {@link Selector#select(Object)}. * * @author chenglu * @date 2021-07-09 21:31 diff --git a/api/src/main/java/com/alibaba/nacos/api/naming/selector/context/SelectorContextBuilder.java b/api/src/main/java/com/alibaba/nacos/api/selector/context/SelectorContextBuilder.java similarity index 78% rename from api/src/main/java/com/alibaba/nacos/api/naming/selector/context/SelectorContextBuilder.java rename to api/src/main/java/com/alibaba/nacos/api/selector/context/SelectorContextBuilder.java index 18b15db26..ff79bfedb 100644 --- a/api/src/main/java/com/alibaba/nacos/api/naming/selector/context/SelectorContextBuilder.java +++ b/api/src/main/java/com/alibaba/nacos/api/selector/context/SelectorContextBuilder.java @@ -15,10 +15,12 @@ * */ -package com.alibaba.nacos.api.naming.selector.context; +package com.alibaba.nacos.api.selector.context; + +import com.alibaba.nacos.api.selector.Selector; /** - * The {@link SelectorContextBuilder} mainly for provide the context for {@link com.alibaba.nacos.api.naming.selector.Selector#select(Object)}. + * The {@link SelectorContextBuilder} mainly for provide the context for {@link Selector#select(Object)}. * It provides {@link #build(Object, Object)} method for build context. And also provide {@link #getContextType()} for get the contextType. * * @author chenglu @@ -27,12 +29,12 @@ package com.alibaba.nacos.api.naming.selector.context; public interface SelectorContextBuilder { /** - * build the context for {@link com.alibaba.nacos.api.naming.selector.Selector#select(Object)}. The user must provide consumer and provider. + * build the context for {@link Selector#select(Object)}. The user must provide consumer and provider. * we provide {@link CmdbContext} for user default who want to use the {@link com.alibaba.nacos.api.naming.pojo.Instance}'s CMDB info. * * @param consumer consumer who launch the select. * @param provider the provides who are selected by consumer. - * @return selectorContext use by {@link com.alibaba.nacos.api.naming.selector.Selector#select(Object)}. + * @return selectorContext use by {@link Selector#select(Object)}. */ T build(C consumer, P provider); diff --git a/naming/src/main/java/com/alibaba/nacos/naming/controllers/ServiceController.java b/naming/src/main/java/com/alibaba/nacos/naming/controllers/ServiceController.java index c067cf5c2..a7f3ae998 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/controllers/ServiceController.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/controllers/ServiceController.java @@ -20,11 +20,15 @@ import com.alibaba.nacos.api.common.Constants; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.naming.CommonParams; import com.alibaba.nacos.api.naming.utils.NamingUtils; -import com.alibaba.nacos.api.selector.SelectorType; +import com.alibaba.nacos.api.selector.Selector; import com.alibaba.nacos.auth.annotation.Secured; import com.alibaba.nacos.auth.common.ActionTypes; +import com.alibaba.nacos.common.model.RestResult; +import com.alibaba.nacos.common.model.RestResultUtils; import com.alibaba.nacos.common.utils.IoUtils; import com.alibaba.nacos.common.utils.JacksonUtils; +import com.alibaba.nacos.common.utils.NumberUtils; +import com.alibaba.nacos.common.utils.StringUtils; import com.alibaba.nacos.core.cluster.ServerMemberManager; import com.alibaba.nacos.core.utils.WebUtils; import com.alibaba.nacos.naming.core.Service; @@ -38,14 +42,11 @@ import com.alibaba.nacos.naming.core.v2.upgrade.UpgradeJudgement; import com.alibaba.nacos.naming.misc.Loggers; import com.alibaba.nacos.naming.misc.UtilsAndCommons; import com.alibaba.nacos.naming.pojo.Subscriber; -import com.alibaba.nacos.naming.selector.LabelSelector; import com.alibaba.nacos.naming.selector.NoneSelector; -import com.alibaba.nacos.naming.selector.Selector; +import com.alibaba.nacos.naming.selector.SelectorManager; import com.alibaba.nacos.naming.web.NamingResourceParser; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.alibaba.nacos.common.utils.StringUtils; -import com.alibaba.nacos.common.utils.NumberUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -61,7 +62,8 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; +import java.util.Objects; +import java.util.Optional; /** * Service operation controller. @@ -90,6 +92,9 @@ public class ServiceController { @Autowired private UpgradeJudgement upgradeJudgement; + @Autowired + private SelectorManager selectorManager; + /** * Create a new service. This API will create a persistence service. * @@ -364,26 +369,33 @@ public class ServiceController { } } + /** + * Get all {@link Selector} types. + * + * @return {@link Selector} types. + */ + @GetMapping("/selector/types") + public RestResult> listSelectorTypes() { + return RestResultUtils.success(selectorManager.getAllSelectorTypes()); + } + private Selector parseSelector(String selectorJsonString) throws Exception { - if (StringUtils.isBlank(selectorJsonString)) { return new NoneSelector(); } JsonNode selectorJson = JacksonUtils.toObj(URLDecoder.decode(selectorJsonString, "UTF-8")); - switch (SelectorType.valueOf(selectorJson.get("type").asText())) { - case none: - return new NoneSelector(); - case label: - String expression = selectorJson.get("expression").asText(); - Set labels = LabelSelector.parseExpression(expression); - LabelSelector labelSelector = new LabelSelector(); - labelSelector.setExpression(expression); - labelSelector.setLabels(labels); - return labelSelector; - default: - throw new NacosException(NacosException.INVALID_PARAM, "not match any type of selector!"); + String type = Optional.ofNullable(selectorJson.get("type")) + .orElseThrow(() -> new NacosException(NacosException.INVALID_PARAM, "not match any type of selector!")) + .asText(); + String expression = Optional.ofNullable(selectorJson.get("expression")) + .map(JsonNode::asText) + .orElse(null); + Selector selector = selectorManager.parseSelector(type, expression); + if (Objects.isNull(selector)) { + throw new NacosException(NacosException.INVALID_PARAM, "not match any type of selector!"); } + return selector; } private ServiceOperator getServiceOperator() { diff --git a/naming/src/main/java/com/alibaba/nacos/naming/controllers/UpgradeOpsController.java b/naming/src/main/java/com/alibaba/nacos/naming/controllers/UpgradeOpsController.java index 6aff3f4da..861ffaeab 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/controllers/UpgradeOpsController.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/controllers/UpgradeOpsController.java @@ -22,11 +22,13 @@ import com.alibaba.nacos.api.naming.CommonParams; import com.alibaba.nacos.api.naming.pojo.Instance; import com.alibaba.nacos.api.naming.pojo.ServiceInfo; import com.alibaba.nacos.api.naming.utils.NamingUtils; -import com.alibaba.nacos.api.selector.SelectorType; +import com.alibaba.nacos.api.selector.Selector; import com.alibaba.nacos.auth.annotation.Secured; import com.alibaba.nacos.auth.common.ActionTypes; import com.alibaba.nacos.common.utils.ConvertUtils; import com.alibaba.nacos.common.utils.JacksonUtils; +import com.alibaba.nacos.common.utils.NumberUtils; +import com.alibaba.nacos.common.utils.StringUtils; import com.alibaba.nacos.core.utils.WebUtils; import com.alibaba.nacos.naming.core.InstanceOperator; import com.alibaba.nacos.naming.core.InstanceOperatorClientImpl; @@ -44,16 +46,14 @@ import com.alibaba.nacos.naming.misc.UtilsAndCommons; import com.alibaba.nacos.naming.monitor.MetricsMonitor; import com.alibaba.nacos.naming.pojo.Subscriber; import com.alibaba.nacos.naming.pojo.instance.HttpRequestInstanceBuilder; -import com.alibaba.nacos.naming.selector.LabelSelector; import com.alibaba.nacos.naming.selector.NoneSelector; -import com.alibaba.nacos.naming.selector.Selector; +import com.alibaba.nacos.naming.selector.SelectorManager; import com.alibaba.nacos.naming.web.CanDistro; import com.alibaba.nacos.naming.web.NamingResourceParser; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import org.apache.commons.collections.CollectionUtils; -import com.alibaba.nacos.common.utils.StringUtils; -import com.alibaba.nacos.common.utils.NumberUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -70,6 +70,8 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -107,6 +109,9 @@ public class UpgradeOpsController { private final UpgradeJudgement upgradeJudgement; + @Autowired + private SelectorManager selectorManager; + public UpgradeOpsController(SwitchDomain switchDomain, ServiceManager serviceManager, ServiceOperatorV1Impl serviceOperatorV1, ServiceOperatorV2Impl serviceOperatorV2, InstanceOperatorServiceImpl instanceServiceV1, InstanceOperatorClientImpl instanceServiceV2, @@ -366,25 +371,22 @@ public class UpgradeOpsController { } private Selector parseSelector(String selectorJsonString) throws Exception { - if (StringUtils.isBlank(selectorJsonString)) { return new NoneSelector(); } - + JsonNode selectorJson = JacksonUtils.toObj(URLDecoder.decode(selectorJsonString, "UTF-8")); - switch (SelectorType.valueOf(selectorJson.get("type").asText())) { - case none: - return new NoneSelector(); - case label: - String expression = selectorJson.get("expression").asText(); - Set labels = LabelSelector.parseExpression(expression); - LabelSelector labelSelector = new LabelSelector(); - labelSelector.setExpression(expression); - labelSelector.setLabels(labels); - return labelSelector; - default: - throw new NacosException(NacosException.INVALID_PARAM, "not match any type of selector!"); + String type = Optional.ofNullable(selectorJson.get("type")) + .orElseThrow(() -> new NacosException(NacosException.INVALID_PARAM, "not match any type of selector!")) + .asText(); + String expression = Optional.ofNullable(selectorJson.get("expression")) + .map(JsonNode::asText) + .orElse(null); + Selector selector = selectorManager.parseSelector(type, expression); + if (Objects.isNull(selector)) { + throw new NacosException(NacosException.INVALID_PARAM, "not match any type of selector!"); } + return selector; } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/InstanceOperatorServiceImpl.java b/naming/src/main/java/com/alibaba/nacos/naming/core/InstanceOperatorServiceImpl.java index 931079d99..e3d0a6b72 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/InstanceOperatorServiceImpl.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/InstanceOperatorServiceImpl.java @@ -22,6 +22,7 @@ import com.alibaba.nacos.api.naming.PreservedMetadataKeys; import com.alibaba.nacos.api.naming.pojo.Instance; import com.alibaba.nacos.api.naming.pojo.ServiceInfo; import com.alibaba.nacos.common.utils.JacksonUtils; +import com.alibaba.nacos.common.utils.StringUtils; import com.alibaba.nacos.naming.core.v2.upgrade.doublewrite.execute.InstanceUpgradeHelper; import com.alibaba.nacos.naming.healthcheck.RsInfo; import com.alibaba.nacos.naming.misc.Loggers; @@ -35,9 +36,9 @@ import com.alibaba.nacos.naming.push.v1.ClientInfo; import com.alibaba.nacos.naming.push.v1.DataSource; import com.alibaba.nacos.naming.push.v1.NamingSubscriberServiceV1Impl; import com.alibaba.nacos.naming.push.v1.PushClient; +import com.alibaba.nacos.naming.selector.SelectorManager; import com.alibaba.nacos.naming.utils.InstanceUtil; import org.apache.commons.collections.CollectionUtils; -import com.alibaba.nacos.common.utils.StringUtils; import org.springframework.stereotype.Component; import java.net.InetSocketAddress; @@ -75,6 +76,8 @@ public class InstanceOperatorServiceImpl implements InstanceOperator { private final InstanceUpgradeHelper instanceUpgradeHelper; + private final SelectorManager selectorManager; + private DataSource pushDataSource = new DataSource() { @Override @@ -98,12 +101,13 @@ public class InstanceOperatorServiceImpl implements InstanceOperator { public InstanceOperatorServiceImpl(ServiceManager serviceManager, SwitchDomain switchDomain, UdpPushService pushService, NamingSubscriberServiceV1Impl subscriberServiceV1, - InstanceUpgradeHelper instanceUpgradeHelper) { + InstanceUpgradeHelper instanceUpgradeHelper, SelectorManager selectorManager) { this.serviceManager = serviceManager; this.switchDomain = switchDomain; this.pushService = pushService; this.subscriberServiceV1 = subscriberServiceV1; this.instanceUpgradeHelper = instanceUpgradeHelper; + this.selectorManager = selectorManager; } @Override @@ -193,7 +197,7 @@ public class InstanceOperatorServiceImpl implements InstanceOperator { // filter ips using selector: if (service.getSelector() != null && StringUtils.isNotBlank(clientIP)) { - srvedIps = service.getSelector().select(clientIP, srvedIps); + srvedIps = selectorManager.select(service.getSelector(), clientIP, srvedIps); } if (CollectionUtils.isEmpty(srvedIps)) { diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/Service.java b/naming/src/main/java/com/alibaba/nacos/naming/core/Service.java index 2e5f1e8a6..ca165f418 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/Service.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/Service.java @@ -17,8 +17,10 @@ package com.alibaba.nacos.naming.core; import com.alibaba.nacos.api.common.Constants; +import com.alibaba.nacos.api.selector.Selector; import com.alibaba.nacos.common.utils.JacksonUtils; import com.alibaba.nacos.common.utils.MD5Utils; +import com.alibaba.nacos.common.utils.StringUtils; import com.alibaba.nacos.naming.consistency.KeyBuilder; import com.alibaba.nacos.naming.consistency.RecordListener; import com.alibaba.nacos.naming.core.v2.upgrade.doublewrite.delay.DoubleWriteEventListener; @@ -31,14 +33,12 @@ import com.alibaba.nacos.naming.misc.UtilsAndCommons; import com.alibaba.nacos.naming.pojo.Record; import com.alibaba.nacos.naming.push.UdpPushService; import com.alibaba.nacos.naming.selector.NoneSelector; -import com.alibaba.nacos.naming.selector.Selector; import com.alibaba.nacos.sys.utils.ApplicationUtils; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.ListUtils; -import com.alibaba.nacos.common.utils.StringUtils; import java.util.ArrayList; import java.util.Collection; diff --git a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadata.java b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadata.java index 121875010..fc859af40 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadata.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadata.java @@ -16,8 +16,8 @@ package com.alibaba.nacos.naming.core.v2.metadata; +import com.alibaba.nacos.api.selector.Selector; import com.alibaba.nacos.naming.selector.NoneSelector; -import com.alibaba.nacos.naming.selector.Selector; import java.io.Serializable; import java.util.Map; @@ -44,7 +44,7 @@ public class ServiceMetadata implements Serializable { private float protectThreshold = 0.0F; /** - * Type of {@link com.alibaba.nacos.naming.selector.Selector}. + * Type of {@link Selector}. */ private Selector selector = new NoneSelector(); diff --git a/naming/src/main/java/com/alibaba/nacos/naming/selector/CmdbLabelSelector.java b/naming/src/main/java/com/alibaba/nacos/naming/selector/CmdbLabelSelector.java deleted file mode 100644 index 551e7ca03..000000000 --- a/naming/src/main/java/com/alibaba/nacos/naming/selector/CmdbLabelSelector.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright 1999-2021 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.alibaba.nacos.naming.selector; - -import com.alibaba.nacos.api.cmdb.pojo.Entity; -import com.alibaba.nacos.api.exception.NacosException; -import com.alibaba.nacos.api.naming.pojo.Instance; -import com.alibaba.nacos.api.naming.selector.AbstractCmdbSelector; -import com.alibaba.nacos.api.naming.selector.Selector; -import com.alibaba.nacos.api.naming.selector.context.CmdbContext; -import com.alibaba.nacos.common.utils.CollectionUtils; -import com.alibaba.nacos.common.utils.StringUtils; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -/** - * The implement of {@link LabelSelector} at new version. The main logic is same with {@link LabelSelector}. - * The {@link CmdbLabelSelector} will return the instances labels in {@link #labels} and providers' label value is same with consumer. - * If none matched, then will return all providers instead of. - * - * @author chenglu - * @date 2021-07-16 16:26 - */ -public class CmdbLabelSelector extends AbstractCmdbSelector { - - private static final String TYPE = "label"; - - /** - * {@link Entity} labels key. - */ - private Set labels; - - /** - * the labels expression. - */ - private String expression; - - public Set getLabels() { - return labels; - } - - public void setLabels(Set labels) { - this.labels = labels; - } - - public String getExpression() { - return expression; - } - - public void setExpression(String expression) { - this.expression = expression; - } - - @Override - protected List doSelect(CmdbContext context) { - if (CollectionUtils.isEmpty(labels)) { - return context.getProviders() - .stream() - .map(CmdbContext.CmdbInstance::getInstance) - .collect(Collectors.toList()); - } - CmdbContext.CmdbInstance consumer = context.getConsumer(); - Map consumerLabels = Optional.ofNullable(consumer.getEntity()) - .map(Entity::getLabels) - .orElse(Collections.emptyMap()); - - // filter the instance if consumer and providers' label values equals. - List result = context.getProviders() - .stream() - .filter(ci -> { - Entity providerEntity = ci.getEntity(); - if (Objects.isNull(providerEntity)) { - return false; - } - Map providerLabels = Optional.ofNullable(ci.getEntity().getLabels()) - .orElse(Collections.emptyMap()); - return labels.stream() - .allMatch(label -> { - String consumerLabelValue = consumerLabels.get(label); - if (StringUtils.isBlank(consumerLabelValue)) { - return false; - } - return Objects.equals(consumerLabelValue, providerLabels.get(label)); - }); - }) - .map(CmdbContext.CmdbInstance::getInstance) - .collect(Collectors.toList()); - - // if none match, then return all providers. - if (CollectionUtils.isEmpty(result)) { - return context.getProviders() - .stream() - .map(CmdbContext.CmdbInstance::getInstance) - .collect(Collectors.toList()); - } - return result; - } - - @Override - public Selector, CmdbContext, String> parse(String condition) throws NacosException { - this.labels = LabelSelector.ExpressionInterpreter.parseExpression(condition); - this.expression = condition; - return this; - } - - @Override - public String getType() { - return TYPE; - } -} diff --git a/naming/src/main/java/com/alibaba/nacos/naming/selector/LabelSelector.java b/naming/src/main/java/com/alibaba/nacos/naming/selector/LabelSelector.java index 01673c4fc..a172b445e 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/selector/LabelSelector.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/selector/LabelSelector.java @@ -1,92 +1,57 @@ /* - * Copyright 1999-2018 Alibaba Group Holding Ltd. + * Copyright 1999-2021 Alibaba Group Holding Ltd. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ package com.alibaba.nacos.naming.selector; -import com.alibaba.nacos.api.cmdb.pojo.PreservedEntityTypes; +import com.alibaba.nacos.api.cmdb.pojo.Entity; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.naming.pojo.Instance; -import com.alibaba.nacos.api.selector.ExpressionSelector; -import com.alibaba.nacos.api.selector.SelectorType; -import com.alibaba.nacos.cmdb.service.CmdbReader; -import com.alibaba.nacos.common.utils.JacksonUtils; -import com.alibaba.nacos.sys.utils.ApplicationUtils; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; - +import com.alibaba.nacos.api.selector.AbstractCmdbSelector; +import com.alibaba.nacos.api.selector.context.CmdbContext; +import com.alibaba.nacos.common.utils.CollectionUtils; import com.alibaba.nacos.common.utils.StringUtils; +import com.alibaba.nacos.naming.selector.interpreter.ExpressionInterpreter; -import java.util.ArrayList; -import java.util.HashSet; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; /** - * A selector to implement a so called same-label-prior rule for service discovery. - *

Backgroup

- * Consider service providers are deployed in two sites i.e. site A and site B, and consumers of this service provider - * are also deployed in site A and site B. So the consumers may want to visit the service provider in current site, thus - * consumers in site A visit service providers in site A and consumers in site B visit service providers in site B. This - * is quite useful to reduce the transfer delay of RPC. This is called same-site-prior strategy. - *

Same Label Prior

- * The same-site-prior strategy covers many circumstances in large companies and we can abstract it to a higher level - * strategy: same-label-prior. + * The implement of {@link com.alibaba.nacos.naming.selector.v1.LabelSelector} at new version. + * The main logic is same with {@link com.alibaba.nacos.naming.selector.v1.LabelSelector}. + * The {@link LabelSelector} will return the instances labels in {@link #labels} and providers' label value is same with consumer. + * If none matched, then will return all providers instead of. * - *

So the idea is that presumed we have built a self-defined or integrated a third-party idc CMDB which stores all - * the labels of all IPs. Then we can filter provider IPs by the consumer IP and we only return the providers who have - * the same label values with consumer. We can define the labels we want to include in the comparison. - * - *

If no provider has the same label value with the consumer, we fall back to give all providers to the consumer. - * Note that this fallback strategy may also be abstracted in future to introduce more kinds of behaviors. - * - * @author nkorange - * @see CmdbReader - * @since 0.7.0 + * @author chenglu + * @date 2021-07-16 16:26 */ -@Deprecated -@JsonTypeInfo(use = Id.NAME, property = "type") -public class LabelSelector extends ExpressionSelector implements Selector { +public class LabelSelector extends AbstractCmdbSelector { - private static final long serialVersionUID = -7381912003505096093L; + private static final String TYPE = "label"; /** - * The labels relevant to this the selector. - * - * @see com.alibaba.nacos.api.cmdb.pojo.Label + * {@link Entity} labels key. */ private Set labels; - private static final Set SUPPORTED_INNER_CONNCETORS = new HashSet<>(); - - private static final Set SUPPORTED_OUTER_CONNCETORS = new HashSet<>(); - - private static final String CONSUMER_PREFIX = "CONSUMER.label."; - - private static final String PROVIDER_PREFIX = "PROVIDER.label."; - - private static final char CEQUAL = '='; - - private static final char CAND = '&'; - - static { - SUPPORTED_INNER_CONNCETORS.add(String.valueOf(CEQUAL)); - SUPPORTED_OUTER_CONNCETORS.add(String.valueOf(CAND)); - JacksonUtils.registerSubtype(LabelSelector.class, SelectorType.label.name()); - } - public Set getLabels() { return labels; } @@ -95,197 +60,58 @@ public class LabelSelector extends ExpressionSelector implements Selector { this.labels = labels; } - public LabelSelector() { - super(); - } - - private CmdbReader getCmdbReader() { - return ApplicationUtils.getBean(CmdbReader.class); - } - - public static Set parseExpression(String expression) throws NacosException { - return ExpressionInterpreter.parseExpression(expression); + @Override + protected List doSelect(CmdbContext context) { + if (CollectionUtils.isEmpty(labels)) { + return context.getProviders() + .stream() + .map(CmdbContext.CmdbInstance::getInstance) + .collect(Collectors.toList()); + } + CmdbContext.CmdbInstance consumer = context.getConsumer(); + Map consumerLabels = Optional.ofNullable(consumer.getEntity()) + .map(Entity::getLabels) + .orElse(Collections.emptyMap()); + + // filter the instance if consumer and providers' label values equals. + List result = context.getProviders() + .stream() + .filter(ci -> { + Entity providerEntity = ci.getEntity(); + if (Objects.isNull(providerEntity)) { + return false; + } + Map providerLabels = Optional.ofNullable(ci.getEntity().getLabels()) + .orElse(Collections.emptyMap()); + return labels.stream() + .allMatch(label -> { + String consumerLabelValue = consumerLabels.get(label); + if (StringUtils.isBlank(consumerLabelValue)) { + return false; + } + return Objects.equals(consumerLabelValue, providerLabels.get(label)); + }); + }) + .map(CmdbContext.CmdbInstance::getInstance) + .collect(Collectors.toList()); + + // if none match, then return all providers. + if (CollectionUtils.isEmpty(result)) { + return context.getProviders() + .stream() + .map(CmdbContext.CmdbInstance::getInstance) + .collect(Collectors.toList()); + } + return result; } @Override - public List select(String consumer, List providers) { - if (labels.isEmpty()) { - return providers; - } - - List instanceList = new ArrayList<>(); - for (T instance : providers) { - - boolean matched = true; - for (String labelName : getLabels()) { - - String consumerLabelValue = getCmdbReader() - .queryLabel(consumer, PreservedEntityTypes.ip.name(), labelName); - - if (StringUtils.isNotBlank(consumerLabelValue) && !StringUtils.equals(consumerLabelValue, - getCmdbReader().queryLabel(instance.getIp(), PreservedEntityTypes.ip.name(), labelName))) { - matched = false; - break; - } - } - if (matched) { - instanceList.add(instance); - } - } - - if (instanceList.isEmpty()) { - return providers; - } - - return instanceList; + protected void doParse(String expression) throws NacosException { + this.labels = ExpressionInterpreter.parseExpression(expression); } - /** - * Expression interpreter for label selector. - * - *

For now it supports very limited set of syntax rules. - */ - public static class ExpressionInterpreter { - - /** - * Parse the label expression. - * - *

Currently we support the very single type of expression: - *

-         *     consumer.labelA = provider.labelA & consumer.labelB = provider.labelB
-         * 
- * Later we will implement a interpreter to parse this expression in a standard LL parser way. - * - * @param expression the label expression to parse - * @return collection of labels - */ - public static Set parseExpression(String expression) throws NacosException { - - if (StringUtils.isBlank(expression)) { - return new HashSet<>(); - } - - expression = StringUtils.deleteWhitespace(expression); - - List elements = getTerms(expression); - Set gotLabels = new HashSet<>(); - int index = 0; - - index = checkInnerSyntax(elements, index); - - if (index == -1) { - throw new NacosException(NacosException.INVALID_PARAM, "parse expression failed!"); - } - - gotLabels.add(elements.get(index++).split(PROVIDER_PREFIX)[1]); - - while (index < elements.size()) { - - index = checkOuterSyntax(elements, index); - - if (index >= elements.size()) { - return gotLabels; - } - - if (index == -1) { - throw new NacosException(NacosException.INVALID_PARAM, "parse expression failed!"); - } - - gotLabels.add(elements.get(index++).split(PROVIDER_PREFIX)[1]); - } - - return gotLabels; - } - - public static List getTerms(String expression) { - - List terms = new ArrayList<>(); - - Set characters = new HashSet<>(); - characters.add(CEQUAL); - characters.add(CAND); - - char[] chars = expression.toCharArray(); - - int lastIndex = 0; - for (int index = 0; index < chars.length; index++) { - char ch = chars[index]; - if (characters.contains(ch)) { - terms.add(expression.substring(lastIndex, index)); - terms.add(expression.substring(index, index + 1)); - index++; - lastIndex = index; - } - } - - terms.add(expression.substring(lastIndex, chars.length)); - - return terms; - } - - private static int skipEmpty(List elements, int start) { - while (start < elements.size() && StringUtils.isBlank(elements.get(start))) { - start++; - } - return start; - } - - private static int checkOuterSyntax(List elements, int start) { - - int index = start; - - index = skipEmpty(elements, index); - if (index >= elements.size()) { - return index; - } - - if (!SUPPORTED_OUTER_CONNCETORS.contains(elements.get(index++))) { - return -1; - } - - return checkInnerSyntax(elements, index); - } - - private static int checkInnerSyntax(List elements, int start) { - - int index = start; - - index = skipEmpty(elements, index); - if (index >= elements.size()) { - return -1; - } - - if (!elements.get(index).startsWith(CONSUMER_PREFIX)) { - return -1; - } - - final String labelConsumer = elements.get(index++).split(CONSUMER_PREFIX)[1]; - - index = skipEmpty(elements, index); - if (index >= elements.size()) { - return -1; - } - - if (!SUPPORTED_INNER_CONNCETORS.contains(elements.get(index++))) { - return -1; - } - - index = skipEmpty(elements, index); - if (index >= elements.size()) { - return -1; - } - - if (!elements.get(index).startsWith(PROVIDER_PREFIX)) { - return -1; - } - - final String labelProvider = elements.get(index).split(PROVIDER_PREFIX)[1]; - - if (!labelConsumer.equals(labelProvider)) { - return -1; - } - - return index; - } + @Override + public String getType() { + return TYPE; } } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/selector/NoneSelector.java b/naming/src/main/java/com/alibaba/nacos/naming/selector/NoneSelector.java index b58c9a258..4b0982ce4 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/selector/NoneSelector.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/selector/NoneSelector.java @@ -1,47 +1,57 @@ /* - * Copyright 1999-2018 Alibaba Group Holding Ltd. + * Copyright 1999-2021 Alibaba Group Holding Ltd. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ package com.alibaba.nacos.naming.selector; +import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.naming.pojo.Instance; -import com.alibaba.nacos.api.selector.SelectorType; -import com.alibaba.nacos.common.utils.JacksonUtils; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; +import com.alibaba.nacos.api.selector.Selector; import java.util.List; /** - * Selector with no filtering. + * Selector with no filtering. The logic is same to {@link com.alibaba.nacos.naming.selector.v1.NoneSelector}. * - * @author nkorange - * @since 0.7.0 + * @author chenglu + * @date 2021-08-04 13:28 */ -@Deprecated -@JsonTypeInfo(use = Id.NAME, property = "type") -public class NoneSelector extends com.alibaba.nacos.api.selector.NoneSelector implements Selector { +public class NoneSelector implements Selector, List, String> { - private static final long serialVersionUID = -3752116616221930677L; + private static final String CONTEXT_TYPE = "NONE"; - static { - JacksonUtils.registerSubtype(NoneSelector.class, SelectorType.none.name()); + private static final String TYPE = "none"; + + @Override + public Selector, List, String> parse(String condition) throws NacosException { + return this; } @Override - public List select(String consumer, List providers) { - return providers; + public List select(List context) { + return context; + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public String getContextType() { + return CONTEXT_TYPE; } } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/selector/SelectorManager.java b/naming/src/main/java/com/alibaba/nacos/naming/selector/SelectorManager.java index fbe585b86..fe1786ff4 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/selector/SelectorManager.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/selector/SelectorManager.java @@ -17,11 +17,13 @@ package com.alibaba.nacos.naming.selector; +import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.naming.pojo.Instance; -import com.alibaba.nacos.api.naming.selector.Selector; -import com.alibaba.nacos.api.naming.selector.context.SelectorContextBuilder; +import com.alibaba.nacos.api.selector.Selector; +import com.alibaba.nacos.api.selector.context.SelectorContextBuilder; import com.alibaba.nacos.common.spi.NacosServiceLoader; import com.alibaba.nacos.common.utils.JacksonUtils; +import com.alibaba.nacos.common.utils.StringUtils; import com.alibaba.nacos.naming.misc.Loggers; import org.springframework.stereotype.Component; @@ -34,6 +36,8 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import static com.alibaba.nacos.api.exception.NacosException.SERVER_ERROR; + /** * {@link SelectorManager} work on init {@link Selector#parse(Object)}, execute {@link Selector#select(Object)} and maintain * the type of {@link Selector} and {@link SelectorContextBuilder}. @@ -125,7 +129,10 @@ public class SelectorManager { * @param condition the condition provide for {@link Selector#parse(Object)}. * @return {@link Selector}. */ - public Selector parseSelector(String type, String condition) { + public Selector parseSelector(String type, String condition) throws NacosException { + if (StringUtils.isBlank(type)) { + return null; + } Class clazz = selectorTypes.get(type); if (Objects.isNull(clazz)) { return null; @@ -136,8 +143,8 @@ public class SelectorManager { return selector; } catch (Exception e) { Loggers.SRV_LOG.warn("[SelectorManager] Parse Selector failed, type: {}, condition: {}.", type, condition, e); + throw new NacosException(SERVER_ERROR, "Selector parses failed: " + e.getMessage()); } - return null; } /** @@ -157,7 +164,12 @@ public class SelectorManager { Loggers.SRV_LOG.info("[SelectorManager] cannot find the contextBuilder of type {}.", selector.getType()); return providers; } - Object context = selectorContextBuilder.build(consumerIp, providers); - return (List) selector.select(context); + try { + Object context = selectorContextBuilder.build(consumerIp, providers); + return (List) selector.select(context); + } catch (Exception e) { + Loggers.SRV_LOG.warn("[SelectorManager] execute select failed, will return all providers.", e); + return providers; + } } } diff --git a/naming/src/main/java/com/alibaba/nacos/naming/selector/context/CmdbSelectorContextBuilder.java b/naming/src/main/java/com/alibaba/nacos/naming/selector/context/CmdbSelectorContextBuilder.java index 9babddfce..489c125d6 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/selector/context/CmdbSelectorContextBuilder.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/selector/context/CmdbSelectorContextBuilder.java @@ -20,8 +20,8 @@ package com.alibaba.nacos.naming.selector.context; import com.alibaba.nacos.api.cmdb.pojo.Entity; import com.alibaba.nacos.api.cmdb.pojo.PreservedEntityTypes; import com.alibaba.nacos.api.naming.pojo.Instance; -import com.alibaba.nacos.api.naming.selector.context.CmdbContext; -import com.alibaba.nacos.api.naming.selector.context.SelectorContextBuilder; +import com.alibaba.nacos.api.selector.context.CmdbContext; +import com.alibaba.nacos.api.selector.context.SelectorContextBuilder; import com.alibaba.nacos.cmdb.service.CmdbReader; import com.alibaba.nacos.sys.utils.ApplicationUtils; diff --git a/naming/src/main/java/com/alibaba/nacos/naming/selector/context/NoneSelectorContextBuilder.java b/naming/src/main/java/com/alibaba/nacos/naming/selector/context/NoneSelectorContextBuilder.java new file mode 100644 index 000000000..e610b80c2 --- /dev/null +++ b/naming/src/main/java/com/alibaba/nacos/naming/selector/context/NoneSelectorContextBuilder.java @@ -0,0 +1,45 @@ +/* + * Copyright 1999-2021 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.naming.selector.context; + +import com.alibaba.nacos.api.naming.pojo.Instance; +import com.alibaba.nacos.api.selector.context.SelectorContextBuilder; + +import java.util.List; + +/** + * The {@link NoneSelectorContextBuilder} will return the provider as context for the {@link com.alibaba.nacos.api.selector.Selector} + * which doesn't need any other resource. + * + * @author chenglu + * @date 2021-08-04 13:31 + */ +public class NoneSelectorContextBuilder implements SelectorContextBuilder, String, List> { + + private static final String CONTEXT_TYPE = "NONE"; + + @Override + public List build(String consumer, List provider) { + return provider; + } + + @Override + public String getContextType() { + return CONTEXT_TYPE; + } +} diff --git a/naming/src/main/java/com/alibaba/nacos/naming/selector/interpreter/ExpressionInterpreter.java b/naming/src/main/java/com/alibaba/nacos/naming/selector/interpreter/ExpressionInterpreter.java new file mode 100644 index 000000000..1317624ca --- /dev/null +++ b/naming/src/main/java/com/alibaba/nacos/naming/selector/interpreter/ExpressionInterpreter.java @@ -0,0 +1,194 @@ +/* + * Copyright 1999-2021 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.naming.selector.interpreter; + +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.common.utils.StringUtils; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Expression interpreter for label selector. + * + *

For now it supports very limited set of syntax rules. + * + * @author nokrange + */ +public class ExpressionInterpreter { + + private static final Set SUPPORTED_INNER_CONNCETORS = new HashSet<>(); + + private static final Set SUPPORTED_OUTER_CONNCETORS = new HashSet<>(); + + private static final String CONSUMER_PREFIX = "CONSUMER.label."; + + private static final String PROVIDER_PREFIX = "PROVIDER.label."; + + private static final char CEQUAL = '='; + + private static final char CAND = '&'; + + static { + SUPPORTED_INNER_CONNCETORS.add(String.valueOf(CEQUAL)); + SUPPORTED_OUTER_CONNCETORS.add(String.valueOf(CAND)); + } + + /** + * Parse the label expression. + * + *

Currently we support the very single type of expression: + *

+     *     consumer.labelA = provider.labelA & consumer.labelB = provider.labelB
+     * 
+ * Later we will implement a interpreter to parse this expression in a standard LL parser way. + * + * @param expression the label expression to parse + * @return collection of labels + */ + public static Set parseExpression(String expression) throws NacosException { + + if (StringUtils.isBlank(expression)) { + return new HashSet<>(); + } + + expression = StringUtils.deleteWhitespace(expression); + + List elements = getTerms(expression); + Set gotLabels = new HashSet<>(); + int index = 0; + + index = checkInnerSyntax(elements, index); + + if (index == -1) { + throw new NacosException(NacosException.INVALID_PARAM, "parse expression failed!"); + } + + gotLabels.add(elements.get(index++).split(PROVIDER_PREFIX)[1]); + + while (index < elements.size()) { + + index = checkOuterSyntax(elements, index); + + if (index >= elements.size()) { + return gotLabels; + } + + if (index == -1) { + throw new NacosException(NacosException.INVALID_PARAM, "parse expression failed!"); + } + + gotLabels.add(elements.get(index++).split(PROVIDER_PREFIX)[1]); + } + + return gotLabels; + } + + public static List getTerms(String expression) { + + List terms = new ArrayList<>(); + + Set characters = new HashSet<>(); + characters.add(CEQUAL); + characters.add(CAND); + + char[] chars = expression.toCharArray(); + + int lastIndex = 0; + for (int index = 0; index < chars.length; index++) { + char ch = chars[index]; + if (characters.contains(ch)) { + terms.add(expression.substring(lastIndex, index)); + terms.add(expression.substring(index, index + 1)); + index++; + lastIndex = index; + } + } + + terms.add(expression.substring(lastIndex, chars.length)); + + return terms; + } + + private static int skipEmpty(List elements, int start) { + while (start < elements.size() && StringUtils.isBlank(elements.get(start))) { + start++; + } + return start; + } + + private static int checkOuterSyntax(List elements, int start) { + + int index = start; + + index = skipEmpty(elements, index); + if (index >= elements.size()) { + return index; + } + + if (!SUPPORTED_OUTER_CONNCETORS.contains(elements.get(index++))) { + return -1; + } + + return checkInnerSyntax(elements, index); + } + + private static int checkInnerSyntax(List elements, int start) { + + int index = start; + + index = skipEmpty(elements, index); + if (index >= elements.size()) { + return -1; + } + + if (!elements.get(index).startsWith(CONSUMER_PREFIX)) { + return -1; + } + + final String labelConsumer = elements.get(index++).split(CONSUMER_PREFIX)[1]; + + index = skipEmpty(elements, index); + if (index >= elements.size()) { + return -1; + } + + if (!SUPPORTED_INNER_CONNCETORS.contains(elements.get(index++))) { + return -1; + } + + index = skipEmpty(elements, index); + if (index >= elements.size()) { + return -1; + } + + if (!elements.get(index).startsWith(PROVIDER_PREFIX)) { + return -1; + } + + final String labelProvider = elements.get(index).split(PROVIDER_PREFIX)[1]; + + if (!labelConsumer.equals(labelProvider)) { + return -1; + } + + return index; + } +} \ No newline at end of file diff --git a/naming/src/main/java/com/alibaba/nacos/naming/selector/v1/LabelSelector.java b/naming/src/main/java/com/alibaba/nacos/naming/selector/v1/LabelSelector.java new file mode 100644 index 000000000..c04c2f1b0 --- /dev/null +++ b/naming/src/main/java/com/alibaba/nacos/naming/selector/v1/LabelSelector.java @@ -0,0 +1,292 @@ +/* + * Copyright 1999-2021 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.naming.selector.v1; + +import com.alibaba.nacos.api.cmdb.pojo.PreservedEntityTypes; +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.pojo.Instance; +import com.alibaba.nacos.api.selector.ExpressionSelector; +import com.alibaba.nacos.api.selector.SelectorType; +import com.alibaba.nacos.cmdb.service.CmdbReader; +import com.alibaba.nacos.common.utils.JacksonUtils; +import com.alibaba.nacos.sys.utils.ApplicationUtils; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; + +import com.alibaba.nacos.common.utils.StringUtils; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * A selector to implement a so called same-label-prior rule for service discovery. + *

Backgroup

+ * Consider service providers are deployed in two sites i.e. site A and site B, and consumers of this service provider + * are also deployed in site A and site B. So the consumers may want to visit the service provider in current site, thus + * consumers in site A visit service providers in site A and consumers in site B visit service providers in site B. This + * is quite useful to reduce the transfer delay of RPC. This is called same-site-prior strategy. + *

Same Label Prior

+ * The same-site-prior strategy covers many circumstances in large companies and we can abstract it to a higher level + * strategy: same-label-prior. + * + *

So the idea is that presumed we have built a self-defined or integrated a third-party idc CMDB which stores all + * the labels of all IPs. Then we can filter provider IPs by the consumer IP and we only return the providers who have + * the same label values with consumer. We can define the labels we want to include in the comparison. + * + *

If no provider has the same label value with the consumer, we fall back to give all providers to the consumer. + * Note that this fallback strategy may also be abstracted in future to introduce more kinds of behaviors. + * + * @author nkorange + * @see CmdbReader + * @since 0.7.0 + */ +@Deprecated +@JsonTypeInfo(use = Id.NAME, property = "type") +public class LabelSelector extends ExpressionSelector implements Selector { + + private static final long serialVersionUID = -7381912003505096093L; + + /** + * The labels relevant to this the selector. + * + * @see com.alibaba.nacos.api.cmdb.pojo.Label + */ + private Set labels; + + private static final Set SUPPORTED_INNER_CONNCETORS = new HashSet<>(); + + private static final Set SUPPORTED_OUTER_CONNCETORS = new HashSet<>(); + + private static final String CONSUMER_PREFIX = "CONSUMER.label."; + + private static final String PROVIDER_PREFIX = "PROVIDER.label."; + + private static final char CEQUAL = '='; + + private static final char CAND = '&'; + + static { + SUPPORTED_INNER_CONNCETORS.add(String.valueOf(CEQUAL)); + SUPPORTED_OUTER_CONNCETORS.add(String.valueOf(CAND)); + JacksonUtils.registerSubtype(LabelSelector.class, SelectorType.label.name()); + } + + public Set getLabels() { + return labels; + } + + public void setLabels(Set labels) { + this.labels = labels; + } + + public LabelSelector() { + super(); + } + + private CmdbReader getCmdbReader() { + return ApplicationUtils.getBean(CmdbReader.class); + } + + public static Set parseExpression(String expression) throws NacosException { + return ExpressionInterpreter.parseExpression(expression); + } + + @Override + public List select(String consumer, List providers) { + if (labels.isEmpty()) { + return providers; + } + + List instanceList = new ArrayList<>(); + for (T instance : providers) { + + boolean matched = true; + for (String labelName : getLabels()) { + + String consumerLabelValue = getCmdbReader() + .queryLabel(consumer, PreservedEntityTypes.ip.name(), labelName); + + if (StringUtils.isNotBlank(consumerLabelValue) && !StringUtils.equals(consumerLabelValue, + getCmdbReader().queryLabel(instance.getIp(), PreservedEntityTypes.ip.name(), labelName))) { + matched = false; + break; + } + } + if (matched) { + instanceList.add(instance); + } + } + + if (instanceList.isEmpty()) { + return providers; + } + + return instanceList; + } + + /** + * Expression interpreter for label selector. + * + *

For now it supports very limited set of syntax rules. + */ + public static class ExpressionInterpreter { + + /** + * Parse the label expression. + * + *

Currently we support the very single type of expression: + *

+         *     consumer.labelA = provider.labelA & consumer.labelB = provider.labelB
+         * 
+ * Later we will implement a interpreter to parse this expression in a standard LL parser way. + * + * @param expression the label expression to parse + * @return collection of labels + */ + public static Set parseExpression(String expression) throws NacosException { + + if (StringUtils.isBlank(expression)) { + return new HashSet<>(); + } + + expression = StringUtils.deleteWhitespace(expression); + + List elements = getTerms(expression); + Set gotLabels = new HashSet<>(); + int index = 0; + + index = checkInnerSyntax(elements, index); + + if (index == -1) { + throw new NacosException(NacosException.INVALID_PARAM, "parse expression failed!"); + } + + gotLabels.add(elements.get(index++).split(PROVIDER_PREFIX)[1]); + + while (index < elements.size()) { + + index = checkOuterSyntax(elements, index); + + if (index >= elements.size()) { + return gotLabels; + } + + if (index == -1) { + throw new NacosException(NacosException.INVALID_PARAM, "parse expression failed!"); + } + + gotLabels.add(elements.get(index++).split(PROVIDER_PREFIX)[1]); + } + + return gotLabels; + } + + public static List getTerms(String expression) { + + List terms = new ArrayList<>(); + + Set characters = new HashSet<>(); + characters.add(CEQUAL); + characters.add(CAND); + + char[] chars = expression.toCharArray(); + + int lastIndex = 0; + for (int index = 0; index < chars.length; index++) { + char ch = chars[index]; + if (characters.contains(ch)) { + terms.add(expression.substring(lastIndex, index)); + terms.add(expression.substring(index, index + 1)); + index++; + lastIndex = index; + } + } + + terms.add(expression.substring(lastIndex, chars.length)); + + return terms; + } + + private static int skipEmpty(List elements, int start) { + while (start < elements.size() && StringUtils.isBlank(elements.get(start))) { + start++; + } + return start; + } + + private static int checkOuterSyntax(List elements, int start) { + + int index = start; + + index = skipEmpty(elements, index); + if (index >= elements.size()) { + return index; + } + + if (!SUPPORTED_OUTER_CONNCETORS.contains(elements.get(index++))) { + return -1; + } + + return checkInnerSyntax(elements, index); + } + + private static int checkInnerSyntax(List elements, int start) { + + int index = start; + + index = skipEmpty(elements, index); + if (index >= elements.size()) { + return -1; + } + + if (!elements.get(index).startsWith(CONSUMER_PREFIX)) { + return -1; + } + + final String labelConsumer = elements.get(index++).split(CONSUMER_PREFIX)[1]; + + index = skipEmpty(elements, index); + if (index >= elements.size()) { + return -1; + } + + if (!SUPPORTED_INNER_CONNCETORS.contains(elements.get(index++))) { + return -1; + } + + index = skipEmpty(elements, index); + if (index >= elements.size()) { + return -1; + } + + if (!elements.get(index).startsWith(PROVIDER_PREFIX)) { + return -1; + } + + final String labelProvider = elements.get(index).split(PROVIDER_PREFIX)[1]; + + if (!labelConsumer.equals(labelProvider)) { + return -1; + } + + return index; + } + } +} diff --git a/naming/src/main/java/com/alibaba/nacos/naming/selector/v1/NoneSelector.java b/naming/src/main/java/com/alibaba/nacos/naming/selector/v1/NoneSelector.java new file mode 100644 index 000000000..03de51621 --- /dev/null +++ b/naming/src/main/java/com/alibaba/nacos/naming/selector/v1/NoneSelector.java @@ -0,0 +1,48 @@ +/* + * Copyright 1999-2021 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.naming.selector.v1; + +import com.alibaba.nacos.api.naming.pojo.Instance; +import com.alibaba.nacos.api.selector.SelectorType; +import com.alibaba.nacos.common.utils.JacksonUtils; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeInfo.Id; + +import java.util.List; + +/** + * Selector with no filtering. + * + * @author nkorange + * @since 0.7.0 + */ +@Deprecated +@JsonTypeInfo(use = Id.NAME, property = "type") +public class NoneSelector extends com.alibaba.nacos.api.selector.NoneSelector implements Selector { + + private static final long serialVersionUID = -3752116616221930677L; + + static { + JacksonUtils.registerSubtype(NoneSelector.class, SelectorType.none.name()); + } + + @Override + public List select(String consumer, List providers) { + return providers; + } +} diff --git a/naming/src/main/java/com/alibaba/nacos/naming/selector/Selector.java b/naming/src/main/java/com/alibaba/nacos/naming/selector/v1/Selector.java similarity index 69% rename from naming/src/main/java/com/alibaba/nacos/naming/selector/Selector.java rename to naming/src/main/java/com/alibaba/nacos/naming/selector/v1/Selector.java index 79c42242d..6e9b4d704 100644 --- a/naming/src/main/java/com/alibaba/nacos/naming/selector/Selector.java +++ b/naming/src/main/java/com/alibaba/nacos/naming/selector/v1/Selector.java @@ -1,20 +1,21 @@ /* - * Copyright 1999-2018 Alibaba Group Holding Ltd. + * Copyright 1999-2021 Alibaba Group Holding Ltd. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ -package com.alibaba.nacos.naming.selector; +package com.alibaba.nacos.naming.selector.v1; import com.alibaba.nacos.api.naming.pojo.Instance; import com.fasterxml.jackson.annotation.JsonTypeInfo; diff --git a/naming/src/main/resources/META-INF/services/com.alibaba.nacos.api.naming.selector.Selector b/naming/src/main/resources/META-INF/services/com.alibaba.nacos.api.selector.Selector similarity index 86% rename from naming/src/main/resources/META-INF/services/com.alibaba.nacos.api.naming.selector.Selector rename to naming/src/main/resources/META-INF/services/com.alibaba.nacos.api.selector.Selector index 126bedb8b..1b74a5183 100644 --- a/naming/src/main/resources/META-INF/services/com.alibaba.nacos.api.naming.selector.Selector +++ b/naming/src/main/resources/META-INF/services/com.alibaba.nacos.api.selector.Selector @@ -15,4 +15,5 @@ # # -com.alibaba.nacos.naming.selector.CmdbLabelSelector \ No newline at end of file +com.alibaba.nacos.naming.selector.LabelSelector +com.alibaba.nacos.naming.selector.NoneSelector \ No newline at end of file diff --git a/naming/src/main/resources/META-INF/services/com.alibaba.nacos.api.naming.selector.context.SelectorContextBuilder b/naming/src/main/resources/META-INF/services/com.alibaba.nacos.api.selector.context.SelectorContextBuilder similarity index 90% rename from naming/src/main/resources/META-INF/services/com.alibaba.nacos.api.naming.selector.context.SelectorContextBuilder rename to naming/src/main/resources/META-INF/services/com.alibaba.nacos.api.selector.context.SelectorContextBuilder index 896f5161a..a666359e0 100644 --- a/naming/src/main/resources/META-INF/services/com.alibaba.nacos.api.naming.selector.context.SelectorContextBuilder +++ b/naming/src/main/resources/META-INF/services/com.alibaba.nacos.api.selector.context.SelectorContextBuilder @@ -15,4 +15,5 @@ # # -com.alibaba.nacos.naming.selector.context.CmdbSelectorContextBuilder \ No newline at end of file +com.alibaba.nacos.naming.selector.context.CmdbSelectorContextBuilder +com.alibaba.nacos.naming.selector.context.NoneSelectorContextBuilder \ No newline at end of file diff --git a/naming/src/test/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadataTest.java b/naming/src/test/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadataTest.java index 4416463e1..c3dc411af 100644 --- a/naming/src/test/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadataTest.java +++ b/naming/src/test/java/com/alibaba/nacos/naming/core/v2/metadata/ServiceMetadataTest.java @@ -16,9 +16,9 @@ package com.alibaba.nacos.naming.core.v2.metadata; +import com.alibaba.nacos.api.selector.Selector; import com.alibaba.nacos.naming.selector.LabelSelector; import com.alibaba.nacos.naming.selector.NoneSelector; -import com.alibaba.nacos.naming.selector.Selector; import org.junit.Assert; import org.junit.Before; import org.junit.Test; diff --git a/naming/src/test/java/com/alibaba/nacos/naming/selector/CmdbLabelSelectorTest.java b/naming/src/test/java/com/alibaba/nacos/naming/selector/CmdbLabelSelectorTest.java deleted file mode 100644 index 592810831..000000000 --- a/naming/src/test/java/com/alibaba/nacos/naming/selector/CmdbLabelSelectorTest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 1999-2021 Alibaba Group Holding Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.alibaba.nacos.naming.selector; - -import com.alibaba.nacos.api.naming.selector.Selector; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -/** - * {@link CmdbLabelSelector} unit test. - * - * @author chenglu - * @date 2021-07-16 17:41 - */ -public class CmdbLabelSelectorTest { - - private SelectorManager selectorManager; - - @Before - public void setUp() { - selectorManager = new SelectorManager(); - selectorManager.init(); - } - - @Test - public void testParseSelector() { - Selector selector = selectorManager.parseSelector("label", "CONSUMER.label.A=PROVIDER.label.A &CONSUMER.label.B=PROVIDER.label.B"); - Assert.assertTrue(selector instanceof CmdbLabelSelector); - - CmdbLabelSelector cmdbLabelSelector = (CmdbLabelSelector) selector; - Assert.assertEquals(2, cmdbLabelSelector.getLabels().size()); - Assert.assertTrue(cmdbLabelSelector.getLabels().contains("A")); - Assert.assertTrue(cmdbLabelSelector.getLabels().contains("B")); - } -} diff --git a/naming/src/test/java/com/alibaba/nacos/naming/selector/LabelSelectorTest.java b/naming/src/test/java/com/alibaba/nacos/naming/selector/LabelSelectorTest.java index ad567c21d..bb85cbc4a 100644 --- a/naming/src/test/java/com/alibaba/nacos/naming/selector/LabelSelectorTest.java +++ b/naming/src/test/java/com/alibaba/nacos/naming/selector/LabelSelectorTest.java @@ -1,43 +1,52 @@ /* - * Copyright 1999-2018 Alibaba Group Holding Ltd. + * Copyright 1999-2021 Alibaba Group Holding Ltd. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ package com.alibaba.nacos.naming.selector; import com.alibaba.nacos.api.exception.NacosException; -import com.alibaba.nacos.common.utils.StringUtils; +import com.alibaba.nacos.api.selector.Selector; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; -import java.util.List; -import java.util.Set; - +/** + * {@link LabelSelector} unit test. + * + * @author chenglu + * @date 2021-07-16 17:41 + */ public class LabelSelectorTest { - private String expression = "CONSUMER.label.A=PROVIDER.label.A &CONSUMER.label.B=PROVIDER.label.B"; + private SelectorManager selectorManager; - @Test - public void parseExpression() throws NacosException { - expression = StringUtils.deleteWhitespace(expression); - List terms = LabelSelector.ExpressionInterpreter.getTerms(expression); - Assert.assertEquals(7, terms.size()); - Set parseLables = LabelSelector.parseExpression(expression); - Assert.assertEquals(2, parseLables.size()); - String[] labs = parseLables.toArray(new String[] {}); - Assert.assertEquals("A", labs[0]); - Assert.assertEquals("B", labs[1]); + @Before + public void setUp() { + selectorManager = new SelectorManager(); + selectorManager.init(); } + @Test + public void testParseSelector() throws NacosException { + Selector selector = selectorManager.parseSelector("label", "CONSUMER.label.A=PROVIDER.label.A &CONSUMER.label.B=PROVIDER.label.B"); + Assert.assertTrue(selector instanceof LabelSelector); + + LabelSelector labelSelector = (LabelSelector) selector; + Assert.assertEquals(2, labelSelector.getLabels().size()); + Assert.assertTrue(labelSelector.getLabels().contains("A")); + Assert.assertTrue(labelSelector.getLabels().contains("B")); + } } diff --git a/naming/src/test/java/com/alibaba/nacos/naming/selector/MockCmdbContextBuilder.java b/naming/src/test/java/com/alibaba/nacos/naming/selector/MockCmdbContextBuilder.java index c5b115e7a..de35856ef 100644 --- a/naming/src/test/java/com/alibaba/nacos/naming/selector/MockCmdbContextBuilder.java +++ b/naming/src/test/java/com/alibaba/nacos/naming/selector/MockCmdbContextBuilder.java @@ -19,8 +19,8 @@ package com.alibaba.nacos.naming.selector; import com.alibaba.nacos.api.cmdb.pojo.Entity; import com.alibaba.nacos.api.naming.pojo.Instance; -import com.alibaba.nacos.api.naming.selector.context.CmdbContext; -import com.alibaba.nacos.api.naming.selector.context.SelectorContextBuilder; +import com.alibaba.nacos.api.selector.context.CmdbContext; +import com.alibaba.nacos.api.selector.context.SelectorContextBuilder; import java.util.HashMap; import java.util.List; diff --git a/naming/src/test/java/com/alibaba/nacos/naming/selector/MockSelector.java b/naming/src/test/java/com/alibaba/nacos/naming/selector/MockSelector.java index ee0656b5a..9b18116bd 100644 --- a/naming/src/test/java/com/alibaba/nacos/naming/selector/MockSelector.java +++ b/naming/src/test/java/com/alibaba/nacos/naming/selector/MockSelector.java @@ -17,10 +17,10 @@ package com.alibaba.nacos.naming.selector; +import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.naming.pojo.Instance; -import com.alibaba.nacos.api.naming.selector.AbstractCmdbSelector; -import com.alibaba.nacos.api.naming.selector.Selector; -import com.alibaba.nacos.api.naming.selector.context.CmdbContext; +import com.alibaba.nacos.api.selector.AbstractCmdbSelector; +import com.alibaba.nacos.api.selector.context.CmdbContext; import java.util.List; import java.util.Map; @@ -73,11 +73,10 @@ public class MockSelector extends AbstractCmdbSelector { } @Override - public Selector, CmdbContext, String> parse(String condition) { - String[] keyValues = condition.split("="); + protected void doParse(String expression) throws NacosException { + String[] keyValues = expression.split("="); key = keyValues[0]; value = keyValues[1]; - return this; } @Override diff --git a/naming/src/test/java/com/alibaba/nacos/naming/selector/SelectorManagerTest.java b/naming/src/test/java/com/alibaba/nacos/naming/selector/SelectorManagerTest.java index 2168fdca3..5dc897ddb 100644 --- a/naming/src/test/java/com/alibaba/nacos/naming/selector/SelectorManagerTest.java +++ b/naming/src/test/java/com/alibaba/nacos/naming/selector/SelectorManagerTest.java @@ -17,8 +17,9 @@ package com.alibaba.nacos.naming.selector; +import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.naming.pojo.Instance; -import com.alibaba.nacos.api.naming.selector.Selector; +import com.alibaba.nacos.api.selector.Selector; import com.alibaba.nacos.consistency.SerializeFactory; import com.alibaba.nacos.consistency.Serializer; import org.junit.Assert; @@ -51,7 +52,7 @@ public class SelectorManagerTest { } @Test - public void testParseSelector() { + public void testParseSelector() throws NacosException { Selector selector = selectorManager.parseSelector("mock", "key=value"); Assert.assertTrue(selector instanceof MockSelector); @@ -59,7 +60,7 @@ public class SelectorManagerTest { } @Test - public void testSelect() { + public void testSelect() throws NacosException { Selector selector = selectorManager.parseSelector("mock", "key=value"); Instance instance = new Instance(); instance.setIp("2.2.2.2"); diff --git a/naming/src/test/java/com/alibaba/nacos/naming/selector/v1/LabelSelectorTest.java b/naming/src/test/java/com/alibaba/nacos/naming/selector/v1/LabelSelectorTest.java new file mode 100644 index 000000000..eb8f09410 --- /dev/null +++ b/naming/src/test/java/com/alibaba/nacos/naming/selector/v1/LabelSelectorTest.java @@ -0,0 +1,43 @@ +/* + * Copyright 1999-2021 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.alibaba.nacos.naming.selector.v1; + +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.common.utils.StringUtils; +import org.junit.Assert; +import org.junit.Test; + +import java.util.List; +import java.util.Set; + +public class LabelSelectorTest { + + private String expression = "CONSUMER.label.A=PROVIDER.label.A &CONSUMER.label.B=PROVIDER.label.B"; + + @Test + public void parseExpression() throws NacosException { + expression = StringUtils.deleteWhitespace(expression); + List terms = LabelSelector.ExpressionInterpreter.getTerms(expression); + Assert.assertEquals(7, terms.size()); + Set parseLables = LabelSelector.parseExpression(expression); + Assert.assertEquals(2, parseLables.size()); + String[] labs = parseLables.toArray(new String[] {}); + Assert.assertEquals("A", labs[0]); + Assert.assertEquals("B", labs[1]); + } +} diff --git a/naming/src/test/resources/META-INF/services/com.alibaba.nacos.api.naming.selector.Selector b/naming/src/test/resources/META-INF/services/com.alibaba.nacos.api.selector.Selector similarity index 100% rename from naming/src/test/resources/META-INF/services/com.alibaba.nacos.api.naming.selector.Selector rename to naming/src/test/resources/META-INF/services/com.alibaba.nacos.api.selector.Selector diff --git a/naming/src/test/resources/META-INF/services/com.alibaba.nacos.api.naming.selector.context.SelectorContextBuilder b/naming/src/test/resources/META-INF/services/com.alibaba.nacos.api.selector.context.SelectorContextBuilder similarity index 100% rename from naming/src/test/resources/META-INF/services/com.alibaba.nacos.api.naming.selector.context.SelectorContextBuilder rename to naming/src/test/resources/META-INF/services/com.alibaba.nacos.api.selector.context.SelectorContextBuilder