Skip to content

Commit 679ce44

Browse files
authored
tag support multi level (#12673)
1 parent 4e9a0a4 commit 679ce44

File tree

4 files changed

+103
-3
lines changed

4 files changed

+103
-3
lines changed

dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,23 @@ public static String join(Collection<String> coll, String split) {
856856
return sb.toString();
857857
}
858858

859+
public static String join(final Object[] array, final char delimiter, final int startIndex, final int endIndex) {
860+
if (ArrayUtils.isEmpty(array)) {
861+
return EMPTY_STRING;
862+
}
863+
if (endIndex - startIndex <= 0) {
864+
return EMPTY_STRING;
865+
}
866+
StringBuilder sb = new StringBuilder();
867+
for (int i = startIndex; i < endIndex; i++) {
868+
if (i > 0) {
869+
sb.append(delimiter);
870+
}
871+
sb.append(array[i]);
872+
}
873+
return sb.toString();
874+
}
875+
859876
/**
860877
* parse key-value pair.
861878
*

dubbo-common/src/test/java/org/apache/dubbo/common/utils/StringUtilsTest.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,10 @@ void testJoin() throws Exception {
227227
assertEquals(StringUtils.join(s), "123");
228228
assertEquals(StringUtils.join(s, ','), "1,2,3");
229229
assertEquals(StringUtils.join(s, ","), "1,2,3");
230+
assertEquals(StringUtils.join(s, ',', 0, 1), "1");
231+
assertEquals(StringUtils.join(s, ',', 0, 2), "1,2");
232+
assertEquals(StringUtils.join(s, ',', 0, 3), "1,2,3");
233+
assertEquals("", StringUtils.join(s, ',', 2, 0), "1,2");
230234
}
231235

232236
@Test
@@ -502,4 +506,4 @@ void testStartsWithIgnoreCase() {
502506
assertTrue(startsWithIgnoreCase("Dubbo.application.name", "dubbo.application."));
503507

504508
}
505-
}
509+
}

dubbo-plugin/dubbo-plugin-router-tag/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagStateRouter.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.apache.dubbo.rpc.cluster.router.tag.model.TagRouterRule;
3737
import org.apache.dubbo.rpc.cluster.router.tag.model.TagRuleParser;
3838

39+
import java.util.Map;
3940
import java.util.Set;
4041
import java.util.function.Predicate;
4142

@@ -52,6 +53,7 @@ public class TagStateRouter<T> extends AbstractStateRouter<T> implements Configu
5253
public static final String NAME = "TAG_ROUTER";
5354
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(TagStateRouter.class);
5455
private static final String RULE_SUFFIX = ".tag-router";
56+
public static final char TAG_SEPERATOR = '|';
5557

5658
private volatile TagRouterRule tagRouterRule;
5759
private String application;
@@ -106,7 +108,8 @@ public BitList<Invoker<T>> doRoute(BitList<Invoker<T>> invokers, URL url, Invoca
106108

107109
// if we are requesting for a Provider with a specific tag
108110
if (StringUtils.isNotEmpty(tag)) {
109-
Set<String> addresses = tagRouterRuleCopy.getTagnameToAddresses().get(tag);
111+
Map<String, Set<String>> tagnameToAddresses = tagRouterRuleCopy.getTagnameToAddresses();
112+
Set<String> addresses = selectAddressByTagLevel(tagnameToAddresses, tag, isForceUseTag(invocation));
110113
// filter by dynamic tag group first
111114
if (addresses != null) { // null means tag not set
112115
result = filterInvoker(invokers, invoker -> addressMatches(invoker.getUrl(), addresses));
@@ -306,4 +309,34 @@ public void stop() {
306309
public void setTagRouterRule(TagRouterRule tagRouterRule) {
307310
this.tagRouterRule = tagRouterRule;
308311
}
312+
313+
/**
314+
* select addresses by tag with level
315+
* <p>
316+
* example:
317+
* selector=beta|team1|partner1
318+
* step1.select tagAddresses with selector=beta|team1|partner1, if result is empty, then run step2
319+
* step2.select tagAddresses with selector=beta|team1, if result is empty, then run step3
320+
* step3.select tagAddresses with selector=beta, if result is empty, result is null
321+
* </p>
322+
*
323+
* @param tagAddresses
324+
* @param tagSelector eg: beta|team1|partner1
325+
* @return
326+
*/
327+
public static Set<String> selectAddressByTagLevel(Map<String, Set<String>> tagAddresses, String tagSelector, boolean isForce) {
328+
if (isForce || StringUtils.isNotContains(tagSelector, TAG_SEPERATOR)) {
329+
return tagAddresses.get(tagSelector);
330+
}
331+
String[] selectors = StringUtils.split(tagSelector, TAG_SEPERATOR);
332+
for (int i = selectors.length; i > 0; i--) {
333+
String selectorTmp = StringUtils.join(selectors, TAG_SEPERATOR, 0, i);
334+
Set<String> addresses = tagAddresses.get(selectorTmp);
335+
if (CollectionUtils.isNotEmpty(addresses)) {
336+
return addresses;
337+
}
338+
}
339+
return null;
340+
}
341+
309342
}

dubbo-plugin/dubbo-plugin-router-tag/src/test/java/org/apache/dubbo/rpc/cluster/router/tag/TagStateRouterTest.java

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,24 @@
2424
import org.apache.dubbo.rpc.Invoker;
2525
import org.apache.dubbo.rpc.RpcInvocation;
2626
import org.apache.dubbo.rpc.cluster.router.MockInvoker;
27-
//import org.apache.dubbo.rpc.cluster.router.mesh.util.TracingContextProvider;
2827
import org.apache.dubbo.rpc.cluster.router.state.BitList;
2928
import org.apache.dubbo.rpc.cluster.router.state.StateRouter;
3029
import org.apache.dubbo.rpc.cluster.router.tag.model.TagRouterRule;
3130
import org.apache.dubbo.rpc.cluster.router.tag.model.TagRuleParser;
3231
import org.apache.dubbo.rpc.model.ApplicationModel;
3332
import org.apache.dubbo.rpc.model.ModuleModel;
3433

34+
import com.google.common.collect.Sets;
3535
import org.junit.jupiter.api.Assertions;
3636
import org.junit.jupiter.api.BeforeEach;
3737
import org.junit.jupiter.api.Test;
3838
import org.mockito.Mockito;
3939

4040
import java.util.ArrayList;
41+
import java.util.HashMap;
4142
import java.util.List;
43+
import java.util.Map;
44+
import java.util.Set;
4245

4346
import static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY;
4447
import static org.mockito.Mockito.when;
@@ -256,4 +259,47 @@ private TagRouterRule getTagRule() {
256259
TagRouterRule tagRouterRule = TagRuleParser.parse(tagRouterRuleConfig);
257260
return tagRouterRule;
258261
}
262+
263+
@Test
264+
public void tagMultiLevelTest() {
265+
String tagSelector = "beta|team1|partner1";
266+
Set<String> address1 = Sets.newHashSet("192.168.5.1:20880");
267+
Map<String, Set<String>> tagAddresses = new HashMap<>();
268+
tagAddresses.put("beta", address1);
269+
Assertions.assertEquals(address1, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));
270+
271+
Set<String> address2 = Sets.newHashSet("192.168.5.2:20880");
272+
tagAddresses.put("beta|team1", address2);
273+
Assertions.assertEquals(address2, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));
274+
275+
Set<String> address3 = Sets.newHashSet("192.168.5.3:20880");
276+
tagAddresses.put("beta|team1|partner1", address3);
277+
Assertions.assertEquals(address3, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));
278+
279+
tagSelector = "beta";
280+
Assertions.assertEquals(address1, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));
281+
tagSelector = "beta|team1";
282+
Assertions.assertEquals(address2, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));
283+
tagSelector = "beta|team1|partner1";
284+
Assertions.assertEquals(address3, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));
285+
286+
tagSelector = "beta2";
287+
Assertions.assertNull(TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));
288+
tagSelector = "beta|team2";
289+
Assertions.assertEquals(address1, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));
290+
tagSelector = "beta|team1|partner2";
291+
Assertions.assertEquals(address2, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false));
292+
293+
294+
}
295+
296+
@Test
297+
public void tagLevelForceTest() {
298+
Set<String> addresses = Sets.newHashSet("192.168.1.223:20880");
299+
Map<String, Set<String>> tagAddresses = new HashMap<>();
300+
tagAddresses.put("beta", addresses);
301+
Set<String> selectedAddresses = TagStateRouter.selectAddressByTagLevel(tagAddresses, "beta", true);
302+
Assertions.assertEquals(addresses, selectedAddresses);
303+
}
304+
259305
}

0 commit comments

Comments
 (0)