* [ISSUE #6301] replace the Selector in 1.x. * [ISSUE #6301] remove the annotation of API(get all selector types).
This commit is contained in:
parent
6a273c9451
commit
9670627724
@ -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<T extends Instance> implements Selector<List<T>, CmdbContext<T>, String> {
|
||||
|
||||
/**
|
||||
* the labels expression.
|
||||
*/
|
||||
protected String expression;
|
||||
|
||||
public String getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
public void setExpression(String expression) {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Selector<List<T>, CmdbContext<T>, 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<T> select(CmdbContext<T> context) {
|
||||
return doSelect(context);
|
@ -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<R, C, D> extends Serializable {
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
||||
public interface Selector<R, C, E> 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<R, C, D> parse(D condition) throws NacosException;
|
||||
Selector<R, C, E> parse(E expression) throws NacosException;
|
||||
|
||||
/**
|
||||
* select the target result.
|
@ -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
|
@ -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<T, C, P> {
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
@ -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 {
|
||||
}
|
||||
}
|
||||
|
||||
private Selector parseSelector(String selectorJsonString) throws Exception {
|
||||
/**
|
||||
* Get all {@link Selector} types.
|
||||
*
|
||||
* @return {@link Selector} types.
|
||||
*/
|
||||
@GetMapping("/selector/types")
|
||||
public RestResult<List<String>> 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<String> labels = LabelSelector.parseExpression(expression);
|
||||
LabelSelector labelSelector = new LabelSelector();
|
||||
labelSelector.setExpression(expression);
|
||||
labelSelector.setLabels(labels);
|
||||
return labelSelector;
|
||||
default:
|
||||
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() {
|
||||
|
@ -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<String> labels = LabelSelector.parseExpression(expression);
|
||||
LabelSelector labelSelector = new LabelSelector();
|
||||
labelSelector.setExpression(expression);
|
||||
labelSelector.setLabels(labels);
|
||||
return labelSelector;
|
||||
default:
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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)) {
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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<T extends Instance> extends AbstractCmdbSelector<T> {
|
||||
|
||||
private static final String TYPE = "label";
|
||||
|
||||
/**
|
||||
* {@link Entity} labels key.
|
||||
*/
|
||||
private Set<String> labels;
|
||||
|
||||
/**
|
||||
* the labels expression.
|
||||
*/
|
||||
private String expression;
|
||||
|
||||
public Set<String> getLabels() {
|
||||
return labels;
|
||||
}
|
||||
|
||||
public void setLabels(Set<String> labels) {
|
||||
this.labels = labels;
|
||||
}
|
||||
|
||||
public String getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
public void setExpression(String expression) {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<T> doSelect(CmdbContext<T> context) {
|
||||
if (CollectionUtils.isEmpty(labels)) {
|
||||
return context.getProviders()
|
||||
.stream()
|
||||
.map(CmdbContext.CmdbInstance::getInstance)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
CmdbContext.CmdbInstance<T> consumer = context.getConsumer();
|
||||
Map<String, String> consumerLabels = Optional.ofNullable(consumer.getEntity())
|
||||
.map(Entity::getLabels)
|
||||
.orElse(Collections.emptyMap());
|
||||
|
||||
// filter the instance if consumer and providers' label values equals.
|
||||
List<T> result = context.getProviders()
|
||||
.stream()
|
||||
.filter(ci -> {
|
||||
Entity providerEntity = ci.getEntity();
|
||||
if (Objects.isNull(providerEntity)) {
|
||||
return false;
|
||||
}
|
||||
Map<String, String> 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<List<T>, CmdbContext<T>, String> parse(String condition) throws NacosException {
|
||||
this.labels = LabelSelector.ExpressionInterpreter.parseExpression(condition);
|
||||
this.expression = condition;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return TYPE;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 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.
|
||||
@ -12,81 +12,46 @@
|
||||
* 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.
|
||||
* <h2>Backgroup</h2>
|
||||
* 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.
|
||||
* <h2>Same Label Prior</h2>
|
||||
* 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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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<T extends Instance> extends AbstractCmdbSelector<T> {
|
||||
|
||||
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<String> labels;
|
||||
|
||||
private static final Set<String> SUPPORTED_INNER_CONNCETORS = new HashSet<>();
|
||||
|
||||
private static final Set<String> 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<String> getLabels() {
|
||||
return labels;
|
||||
}
|
||||
@ -95,197 +60,58 @@ public class LabelSelector extends ExpressionSelector implements Selector {
|
||||
this.labels = labels;
|
||||
}
|
||||
|
||||
public LabelSelector() {
|
||||
super();
|
||||
@Override
|
||||
protected List<T> doSelect(CmdbContext<T> context) {
|
||||
if (CollectionUtils.isEmpty(labels)) {
|
||||
return context.getProviders()
|
||||
.stream()
|
||||
.map(CmdbContext.CmdbInstance::getInstance)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
CmdbContext.CmdbInstance<T> consumer = context.getConsumer();
|
||||
Map<String, String> consumerLabels = Optional.ofNullable(consumer.getEntity())
|
||||
.map(Entity::getLabels)
|
||||
.orElse(Collections.emptyMap());
|
||||
|
||||
private CmdbReader getCmdbReader() {
|
||||
return ApplicationUtils.getBean(CmdbReader.class);
|
||||
// filter the instance if consumer and providers' label values equals.
|
||||
List<T> result = context.getProviders()
|
||||
.stream()
|
||||
.filter(ci -> {
|
||||
Entity providerEntity = ci.getEntity();
|
||||
if (Objects.isNull(providerEntity)) {
|
||||
return false;
|
||||
}
|
||||
Map<String, String> 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());
|
||||
|
||||
public static Set<String> parseExpression(String expression) throws NacosException {
|
||||
return ExpressionInterpreter.parseExpression(expression);
|
||||
// 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 <T extends Instance> List<T> select(String consumer, List<T> providers) {
|
||||
if (labels.isEmpty()) {
|
||||
return providers;
|
||||
protected void doParse(String expression) throws NacosException {
|
||||
this.labels = ExpressionInterpreter.parseExpression(expression);
|
||||
}
|
||||
|
||||
List<T> 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.
|
||||
*
|
||||
* <p>For now it supports very limited set of syntax rules.
|
||||
*/
|
||||
public static class ExpressionInterpreter {
|
||||
|
||||
/**
|
||||
* Parse the label expression.
|
||||
*
|
||||
* <p>Currently we support the very single type of expression:
|
||||
* <pre>
|
||||
* consumer.labelA = provider.labelA & consumer.labelB = provider.labelB
|
||||
* </pre>
|
||||
* 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<String> parseExpression(String expression) throws NacosException {
|
||||
|
||||
if (StringUtils.isBlank(expression)) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
expression = StringUtils.deleteWhitespace(expression);
|
||||
|
||||
List<String> elements = getTerms(expression);
|
||||
Set<String> 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<String> getTerms(String expression) {
|
||||
|
||||
List<String> terms = new ArrayList<>();
|
||||
|
||||
Set<Character> 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<String> elements, int start) {
|
||||
while (start < elements.size() && StringUtils.isBlank(elements.get(start))) {
|
||||
start++;
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
private static int checkOuterSyntax(List<String> 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<String> 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;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 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.
|
||||
@ -12,36 +12,46 @@
|
||||
* 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<T extends Instance> implements Selector<List<T>, List<T>, 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<T>, List<T>, String> parse(String condition) throws NacosException {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Instance> List<T> select(String consumer, List<T> providers) {
|
||||
return providers;
|
||||
public List<T> select(List<T> context) {
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContextType() {
|
||||
return CONTEXT_TYPE;
|
||||
}
|
||||
}
|
||||
|
@ -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<? extends Selector> 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;
|
||||
}
|
||||
try {
|
||||
Object context = selectorContextBuilder.build(consumerIp, providers);
|
||||
return (List<T>) selector.select(context);
|
||||
} catch (Exception e) {
|
||||
Loggers.SRV_LOG.warn("[SelectorManager] execute select failed, will return all providers.", e);
|
||||
return providers;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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<T extends Instance> implements SelectorContextBuilder<List<T>, String, List<T>> {
|
||||
|
||||
private static final String CONTEXT_TYPE = "NONE";
|
||||
|
||||
@Override
|
||||
public List<T> build(String consumer, List<T> provider) {
|
||||
return provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContextType() {
|
||||
return CONTEXT_TYPE;
|
||||
}
|
||||
}
|
@ -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.
|
||||
*
|
||||
* <p>For now it supports very limited set of syntax rules.
|
||||
*
|
||||
* @author nokrange
|
||||
*/
|
||||
public class ExpressionInterpreter {
|
||||
|
||||
private static final Set<String> SUPPORTED_INNER_CONNCETORS = new HashSet<>();
|
||||
|
||||
private static final Set<String> 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.
|
||||
*
|
||||
* <p>Currently we support the very single type of expression:
|
||||
* <pre>
|
||||
* consumer.labelA = provider.labelA & consumer.labelB = provider.labelB
|
||||
* </pre>
|
||||
* 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<String> parseExpression(String expression) throws NacosException {
|
||||
|
||||
if (StringUtils.isBlank(expression)) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
expression = StringUtils.deleteWhitespace(expression);
|
||||
|
||||
List<String> elements = getTerms(expression);
|
||||
Set<String> 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<String> getTerms(String expression) {
|
||||
|
||||
List<String> terms = new ArrayList<>();
|
||||
|
||||
Set<Character> 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<String> elements, int start) {
|
||||
while (start < elements.size() && StringUtils.isBlank(elements.get(start))) {
|
||||
start++;
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
private static int checkOuterSyntax(List<String> 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<String> 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;
|
||||
}
|
||||
}
|
@ -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.
|
||||
* <h2>Backgroup</h2>
|
||||
* 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.
|
||||
* <h2>Same Label Prior</h2>
|
||||
* The same-site-prior strategy covers many circumstances in large companies and we can abstract it to a higher level
|
||||
* strategy: same-label-prior.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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<String> labels;
|
||||
|
||||
private static final Set<String> SUPPORTED_INNER_CONNCETORS = new HashSet<>();
|
||||
|
||||
private static final Set<String> 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<String> getLabels() {
|
||||
return labels;
|
||||
}
|
||||
|
||||
public void setLabels(Set<String> labels) {
|
||||
this.labels = labels;
|
||||
}
|
||||
|
||||
public LabelSelector() {
|
||||
super();
|
||||
}
|
||||
|
||||
private CmdbReader getCmdbReader() {
|
||||
return ApplicationUtils.getBean(CmdbReader.class);
|
||||
}
|
||||
|
||||
public static Set<String> parseExpression(String expression) throws NacosException {
|
||||
return ExpressionInterpreter.parseExpression(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Instance> List<T> select(String consumer, List<T> providers) {
|
||||
if (labels.isEmpty()) {
|
||||
return providers;
|
||||
}
|
||||
|
||||
List<T> 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.
|
||||
*
|
||||
* <p>For now it supports very limited set of syntax rules.
|
||||
*/
|
||||
public static class ExpressionInterpreter {
|
||||
|
||||
/**
|
||||
* Parse the label expression.
|
||||
*
|
||||
* <p>Currently we support the very single type of expression:
|
||||
* <pre>
|
||||
* consumer.labelA = provider.labelA & consumer.labelB = provider.labelB
|
||||
* </pre>
|
||||
* 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<String> parseExpression(String expression) throws NacosException {
|
||||
|
||||
if (StringUtils.isBlank(expression)) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
expression = StringUtils.deleteWhitespace(expression);
|
||||
|
||||
List<String> elements = getTerms(expression);
|
||||
Set<String> 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<String> getTerms(String expression) {
|
||||
|
||||
List<String> terms = new ArrayList<>();
|
||||
|
||||
Set<Character> 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<String> elements, int start) {
|
||||
while (start < elements.size() && StringUtils.isBlank(elements.get(start))) {
|
||||
start++;
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
private static int checkOuterSyntax(List<String> 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<String> 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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 <T extends Instance> List<T> select(String consumer, List<T> providers) {
|
||||
return providers;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 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.
|
||||
@ -12,9 +12,10 @@
|
||||
* 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;
|
@ -15,4 +15,5 @@
|
||||
#
|
||||
#
|
||||
|
||||
com.alibaba.nacos.naming.selector.CmdbLabelSelector
|
||||
com.alibaba.nacos.naming.selector.LabelSelector
|
||||
com.alibaba.nacos.naming.selector.NoneSelector
|
@ -16,3 +16,4 @@
|
||||
#
|
||||
|
||||
com.alibaba.nacos.naming.selector.context.CmdbSelectorContextBuilder
|
||||
com.alibaba.nacos.naming.selector.context.NoneSelectorContextBuilder
|
@ -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;
|
||||
|
@ -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"));
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 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.
|
||||
@ -12,32 +12,41 @@
|
||||
* 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;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
selectorManager = new SelectorManager();
|
||||
selectorManager.init();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseExpression() throws NacosException {
|
||||
expression = StringUtils.deleteWhitespace(expression);
|
||||
List<String> terms = LabelSelector.ExpressionInterpreter.getTerms(expression);
|
||||
Assert.assertEquals(7, terms.size());
|
||||
Set<String> 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]);
|
||||
}
|
||||
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"));
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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<Instance> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Selector<List<Instance>, CmdbContext<Instance>, 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
|
||||
|
@ -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");
|
||||
|
@ -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<String> terms = LabelSelector.ExpressionInterpreter.getTerms(expression);
|
||||
Assert.assertEquals(7, terms.size());
|
||||
Set<String> 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]);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user