This is an automated email from the ASF dual-hosted git repository.
likeguo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git
The following commit(s) were added to refs/heads/master by this push:
new f7f0d49d5 [type:refactor] refactor shenyu trie (#4536)
f7f0d49d5 is described below
commit f7f0d49d55a74005789827eeef75914283f93bb6
Author: moremind <[email protected]>
AuthorDate: Sun Apr 9 21:52:31 2023 +0800
[type:refactor] refactor shenyu trie (#4536)
* [type:refactor] rename shenyu trie
* [type:refactor] rename shenyu trie
* fix ci
---
.../apache/shenyu/common/config/ShenyuConfig.java | 6 +-
...eMatchModeEvent.java => TrieMatchModeEnum.java} | 19 +-
.../base/cache/CommonPluginDataSubscriber.java | 18 +-
.../apache/shenyu/plugin/base/trie/ShenyuTrie.java | 438 +++++++++++----------
.../plugin/base/AbstractShenyuPluginTest.java | 4 +-
.../base/cache/CommonPluginDataSubscriberTest.java | 7 +-
.../shenyu/plugin/base/trie/ShenyuTrieTest.java | 143 ++++---
.../starter/gateway/ShenyuConfiguration.java | 7 +-
.../web/controller/LocalPluginControllerTest.java | 7 +-
9 files changed, 377 insertions(+), 272 deletions(-)
diff --git
a/shenyu-common/src/main/java/org/apache/shenyu/common/config/ShenyuConfig.java
b/shenyu-common/src/main/java/org/apache/shenyu/common/config/ShenyuConfig.java
index c9a9a4723..358cc5ee1 100644
---
a/shenyu-common/src/main/java/org/apache/shenyu/common/config/ShenyuConfig.java
+++
b/shenyu-common/src/main/java/org/apache/shenyu/common/config/ShenyuConfig.java
@@ -19,7 +19,7 @@ package org.apache.shenyu.common.config;
import org.apache.commons.lang3.StringUtils;
import org.apache.shenyu.common.concurrent.MemoryLimitCalculator;
-import org.apache.shenyu.common.enums.TrieMatchModeEvent;
+import org.apache.shenyu.common.enums.TrieMatchModeEnum;
import java.util.ArrayList;
import java.util.HashSet;
@@ -1857,9 +1857,9 @@ public class ShenyuConfig {
/**
* match mode.
- * @see TrieMatchModeEvent
+ * @see TrieMatchModeEnum
*/
- private String matchMode =
TrieMatchModeEvent.ANT_PATH_MATCH.getMatchMode();
+ private String matchMode =
TrieMatchModeEnum.ANT_PATH_MATCH.getMatchMode();
/**
* get match enabled.
diff --git
a/shenyu-common/src/main/java/org/apache/shenyu/common/enums/TrieMatchModeEvent.java
b/shenyu-common/src/main/java/org/apache/shenyu/common/enums/TrieMatchModeEnum.java
similarity index 66%
rename from
shenyu-common/src/main/java/org/apache/shenyu/common/enums/TrieMatchModeEvent.java
rename to
shenyu-common/src/main/java/org/apache/shenyu/common/enums/TrieMatchModeEnum.java
index 8bc51d374..a339cd178 100644
---
a/shenyu-common/src/main/java/org/apache/shenyu/common/enums/TrieMatchModeEvent.java
+++
b/shenyu-common/src/main/java/org/apache/shenyu/common/enums/TrieMatchModeEnum.java
@@ -17,10 +17,12 @@
package org.apache.shenyu.common.enums;
+import java.util.Arrays;
+
/**
* Shenyu match mode event.
*/
-public enum TrieMatchModeEvent {
+public enum TrieMatchModeEnum {
/**
* ant path match.
*/
@@ -33,7 +35,7 @@ public enum TrieMatchModeEvent {
private final String matchMode;
- TrieMatchModeEvent(final String matchMode) {
+ TrieMatchModeEnum(final String matchMode) {
this.matchMode = matchMode;
}
@@ -45,4 +47,17 @@ public enum TrieMatchModeEvent {
public String getMatchMode() {
return matchMode;
}
+
+ /**
+ * get {@linkplain TrieMatchModeEnum} by match mode.
+ *
+ * @param matchMode match mode
+ * @return {@linkplain TrieMatchModeEnum}
+ */
+ public static TrieMatchModeEnum acquireTrieMatch(final String matchMode) {
+ return Arrays.stream(TrieMatchModeEnum.values())
+ .filter(e -> e.getMatchMode().equals(matchMode))
+ .findFirst()
+ .orElseThrow(() -> new IllegalArgumentException("Shenyu trie
match mode is error, match mode:" + matchMode));
+ }
}
diff --git
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriber.java
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriber.java
index 49d49060f..9121037f6 100644
---
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriber.java
+++
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriber.java
@@ -18,6 +18,7 @@
package org.apache.shenyu.plugin.base.cache;
import org.apache.commons.collections4.CollectionUtils;
+import org.apache.shenyu.common.config.ShenyuConfig.ShenyuTrieConfig;
import org.apache.shenyu.common.dto.PluginData;
import org.apache.shenyu.common.dto.RuleData;
import org.apache.shenyu.common.dto.SelectorData;
@@ -51,14 +52,18 @@ public class CommonPluginDataSubscriber implements
PluginDataSubscriber {
private final Map<String, PluginDataHandler> handlerMap;
private ApplicationEventPublisher eventPublisher;
+
+ private final ShenyuTrieConfig shenyuTrieConfig;
/**
* Instantiates a new Common plugin data subscriber.
*
* @param pluginDataHandlerList the plugin data handler list
+ * @param shenyuTrieConfig shenyu trie config
*/
- public CommonPluginDataSubscriber(final List<PluginDataHandler>
pluginDataHandlerList) {
+ public CommonPluginDataSubscriber(final List<PluginDataHandler>
pluginDataHandlerList, final ShenyuTrieConfig shenyuTrieConfig) {
this.handlerMap =
pluginDataHandlerList.stream().collect(Collectors.toConcurrentMap(PluginDataHandler::pluginNamed,
e -> e));
+ this.shenyuTrieConfig = shenyuTrieConfig;
}
/**
@@ -66,11 +71,14 @@ public class CommonPluginDataSubscriber implements
PluginDataSubscriber {
*
* @param pluginDataHandlerList the plugin data handler list
* @param eventPublisher eventPublisher is used to publish sort
plugin event
+ * @param shenyuTrieConfig shenyu trie config
*/
public CommonPluginDataSubscriber(final List<PluginDataHandler>
pluginDataHandlerList,
- final ApplicationEventPublisher
eventPublisher) {
+ final ApplicationEventPublisher
eventPublisher,
+ final ShenyuTrieConfig shenyuTrieConfig)
{
this.handlerMap =
pluginDataHandlerList.stream().collect(Collectors.toConcurrentMap(PluginDataHandler::pluginNamed,
e -> e));
this.eventPublisher = eventPublisher;
+ this.shenyuTrieConfig = shenyuTrieConfig;
}
/**
@@ -207,6 +215,9 @@ public class CommonPluginDataSubscriber implements
PluginDataSubscriber {
Optional.ofNullable(handlerMap.get(ruleData.getPluginName()))
.ifPresent(handler -> handler.handlerRule(ruleData));
MatchDataCache.getInstance().removeRuleData(ruleData.getPluginName());
+ if (!shenyuTrieConfig.getEnabled()) {
+ return;
+ }
if (ruleData.getEnabled()) {
if
(CollectionUtils.isEmpty(ruleData.getBeforeConditionDataList())) {
eventPublisher.publishEvent(new
RuleTrieEvent(RuleTrieEventEnum.INSERT, ruleData));
@@ -262,6 +273,9 @@ public class CommonPluginDataSubscriber implements
PluginDataSubscriber {
Optional.ofNullable(handlerMap.get(ruleData.getPluginName()))
.ifPresent(handler -> handler.removeRule(ruleData));
MatchDataCache.getInstance().removeRuleData(ruleData.getPluginName());
+ if (!shenyuTrieConfig.getEnabled()) {
+ return;
+ }
eventPublisher.publishEvent(new
RuleTrieEvent(RuleTrieEventEnum.REMOVE, ruleData));
}
}
diff --git
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/trie/ShenyuTrie.java
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/trie/ShenyuTrie.java
index 8a04f0114..08a539ad4 100644
---
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/trie/ShenyuTrie.java
+++
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/trie/ShenyuTrie.java
@@ -19,23 +19,29 @@ package org.apache.shenyu.plugin.base.trie;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.shenyu.common.cache.WindowTinyLFUMap;
import org.apache.shenyu.common.dto.RuleData;
-import org.apache.shenyu.common.enums.TrieMatchModeEvent;
+import org.apache.shenyu.common.enums.TrieMatchModeEnum;
+import org.apache.shenyu.common.exception.ShenyuException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.util.Arrays;
+import java.util.BitSet;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
-import java.util.stream.Collectors;
public class ShenyuTrie {
-
+
+ private static final Logger LOG =
LoggerFactory.getLogger(ShenyuTrie.class);
+
private static final String WILDCARD = "*";
private static final String MATCH_ALL = "**";
@@ -49,7 +55,7 @@ public class ShenyuTrie {
private final Long pathVariableSize;
/**
- * the mode includes antPathMatch and pathPattern, please see {@linkplain
TrieMatchModeEvent}.
+ * the mode includes antPathMatch and pathPattern, please see {@linkplain
TrieMatchModeEnum}.
* antPathMatch means all full match, pathPattern is used in web.
*/
private final String matchMode;
@@ -97,124 +103,57 @@ public class ShenyuTrie {
}
/**
- * put node to trie.
+ * put node to trie, shenyu trie support *, **, path, pathVariable
parameters.<br>
+ * <p>* means match 0 or more character</p>
+ * <p>** means match 0 or more dictory directory</p>
+ * <p>pathVariable maybe like {name}</p>
*
* @param uriPath uri path
* @param ruleData rule data
* @param bizInfo biz info
+ * @see org.springframework.util.AntPathMatcher
+ * @see org.springframework.web.util.pattern.PathPattern
*/
public void putNode(final String uriPath, final RuleData ruleData, final
Object bizInfo) {
if (StringUtils.isNotBlank(uriPath)) {
String strippedPath = StringUtils.strip(uriPath, "/");
String[] pathParts = StringUtils.split(strippedPath, "/");
- if (pathParts.length > 0) {
- ShenyuTrieNode node = root;
- for (int i = 0; i < pathParts.length; i++) {
- boolean endOfPath = isMatchAllOrWildcard(pathParts[i]) &&
judgeEqual(i, pathParts.length - 1);
- node = putNode0(pathParts[i], node, matchMode, endOfPath);
- if (Objects.isNull(node)) {
- return;
- }
- }
- // after insert node, set full path and end of path
- node.setFullPath(uriPath);
- node.setEndOfPath(true);
- node.setSelectorId(ruleData.getSelectorId());
- node.setBizInfo(bizInfo);
- if (Objects.isNull(node.getPathRuleCache())) {
- node.setPathRuleCache(new
WindowTinyLFUMap<>(pathRuleCacheSize));
- }
- List<RuleData> ruleDataList = getVal(node.getPathRuleCache(),
ruleData.getSelectorId());
- if (CollectionUtils.isNotEmpty(ruleDataList)) {
- // synchronized list
- synchronized (ruleData.getSelectorId()) {
- ruleDataList.add(ruleData);
-
ruleDataList.sort(Comparator.comparing(RuleData::getSort));
- node.getPathRuleCache().put(ruleData.getSelectorId(),
ruleDataList);
- }
- } else {
- node.getPathRuleCache().put(ruleData.getSelectorId(),
Lists.newArrayList(ruleData));
- }
+ if (ArrayUtils.isEmpty(pathParts)) {
+ return;
}
- }
- }
-
- /**
- * put node to trie.
- *
- * @param segment current string
- * @param shenyuTrieNode current trie node
- * @param matchMode match mode
- * @param isPathEnd end path
- * @return {@linkplain ShenyuTrieNode}
- */
- private ShenyuTrieNode putNode0(final String segment, final ShenyuTrieNode
shenyuTrieNode,
- final String matchMode, final boolean
isPathEnd) {
- // if match mode is path pattern, when segment is * and **, return
current node
- if (TrieMatchModeEvent.PATH_PATTERN.getMatchMode().equals(matchMode)) {
- if (isMatchAll(segment)) {
- // put node, and return node
- return this.put(segment, shenyuTrieNode, true);
- }
- if (isMatchWildcard(segment)) {
- ShenyuTrieNode wildcardNode = this.put(segment,
shenyuTrieNode, true);
- wildcardNode.setWildcard(true);
- return wildcardNode;
+ ShenyuTrieNode node = root;
+ TrieMatchModeEnum trieMatchMode =
TrieMatchModeEnum.acquireTrieMatch(matchMode);
+ if (trieMatchMode.equals(TrieMatchModeEnum.PATH_PATTERN)) {
+ checkLegalPath(uriPath, pathParts);
}
- }
- if
(TrieMatchModeEvent.ANT_PATH_MATCH.getMatchMode().equals(matchMode)) {
- if (isMatchAll(segment) && isPathEnd) {
- return this.put(segment, shenyuTrieNode, true);
+ for (int i = 0; i < pathParts.length; i++) {
+ boolean pathEnd = judgeEqual(i, pathParts.length - 1);
+ node = putNode0(pathParts[i], node, pathEnd);
+ if (Objects.isNull(node)) {
+ remove(StringUtils.join(pathParts, "/", 0, i), ruleData);
+ return;
+ }
}
- if (isMatchWildcard(segment) && isPathEnd) {
- ShenyuTrieNode wildcardNode = this.put(segment,
shenyuTrieNode, true);
- wildcardNode.setWildcard(true);
- return wildcardNode;
+ // after insert node, set full path and end of path
+ node.setFullPath(uriPath);
+ node.setEndOfPath(true);
+ node.setSelectorId(ruleData.getSelectorId());
+ node.setBizInfo(bizInfo);
+ if (Objects.isNull(node.getPathRuleCache())) {
+ node.setPathRuleCache(new
WindowTinyLFUMap<>(pathRuleCacheSize));
}
- }
- // dynamic route
- if (isPathVariable(segment)) {
- ShenyuTrieNode childNode;
- // contains key, get current pathVariable node
- if (containsKey(shenyuTrieNode.getPathVariablesSet(), segment)) {
- childNode = getVal(shenyuTrieNode.getPathVariablesSet(),
segment);
- } else {
- childNode = new ShenyuTrieNode();
- childNode.setMatchStr(segment);
- childNode.setEndOfPath(false);
- if (Objects.isNull(shenyuTrieNode.getPathVariablesSet())) {
- shenyuTrieNode.setPathVariablesSet(new
WindowTinyLFUMap<>(pathVariableSize));
+ List<RuleData> ruleDataList = getVal(node.getPathRuleCache(),
ruleData.getSelectorId());
+ if (CollectionUtils.isNotEmpty(ruleDataList)) {
+ // synchronized list
+ synchronized (ruleData.getId()) {
+ ruleDataList.add(ruleData);
+ ruleDataList.sort(Comparator.comparing(RuleData::getSort));
+ node.getPathRuleCache().put(ruleData.getSelectorId(),
ruleDataList);
}
- shenyuTrieNode.getPathVariablesSet().put(segment, childNode);
- shenyuTrieNode.setPathVariableNode(childNode);
+ } else {
+ node.getPathRuleCache().put(ruleData.getSelectorId(),
Lists.newArrayList(ruleData));
}
- return childNode;
- }
- return this.put(segment, shenyuTrieNode, false);
- }
-
- /**
- * put node.
- *
- * @param segment segment
- * @param shenyuTrieNode shenyu trie node
- * @param endOfPath end of path
- * @return ShenyuTrieNode
- */
- private ShenyuTrieNode put(final String segment, final ShenyuTrieNode
shenyuTrieNode, final boolean endOfPath) {
- if (Objects.isNull(shenyuTrieNode.getChildren())) {
- shenyuTrieNode.setChildren(new WindowTinyLFUMap<>(childrenSize));
- }
- ShenyuTrieNode childrenNode;
- if (containsKey(shenyuTrieNode.getChildren(), segment)) {
- childrenNode = getVal(shenyuTrieNode.getChildren(), segment);
- } else {
- childrenNode = new ShenyuTrieNode();
- childrenNode.setMatchStr(segment);
- childrenNode.setEndOfPath(endOfPath);
- shenyuTrieNode.getChildren().put(segment, childrenNode);
}
- return childrenNode;
}
/**
@@ -225,72 +164,66 @@ public class ShenyuTrie {
* @return {@linkplain ShenyuTrieNode}
*/
public ShenyuTrieNode match(final String uriPath, final String selectorId)
{
- Objects.requireNonNull(selectorId);
- if (!StringUtils.isEmpty(uriPath)) {
- String strippedPath = StringUtils.strip(uriPath, "/");
- String[] pathParts = StringUtils.split(strippedPath, "/");
- if (pathParts.length > 0) {
- ShenyuTrieNode currentNode = root;
- for (int i = 0; i < pathParts.length; i++) {
- String path = pathParts[i];
- boolean endPath = judgeEqual(i, pathParts.length - 1);
- currentNode = matchNode(path, currentNode, selectorId,
endPath, pathParts[pathParts.length - 1]);
- if (Objects.nonNull(currentNode)) {
- // path is not end, continue to execute
- if (checkChildrenNotNull(currentNode) &&
!currentNode.getEndOfPath()) {
- continue;
- }
- // include path variable node, general node, wildcard
node
- if (endPath && checkPathRuleNotNull(currentNode)
- &&
CollectionUtils.isNotEmpty(getVal(currentNode.getPathRuleCache(), selectorId)))
{
- return currentNode;
- }
- // path is end and the match str is **, means match all
- if (isMatchAll(currentNode.getMatchStr()) &&
currentNode.getEndOfPath()
- && checkPathRuleNotNull(currentNode)
- &&
CollectionUtils.isNotEmpty(getVal(currentNode.getPathRuleCache(), selectorId)))
{
- return currentNode;
- }
- } else {
- return null;
- }
- }
- }
+ String strippedPath = StringUtils.strip(uriPath, "/");
+ String[] pathParts = StringUtils.split(strippedPath, "/");
+ if (ArrayUtils.isEmpty(pathParts)) {
+ return null;
}
- return null;
- }
-
- /**
- * match node.
- * <p> priority: path > * > ** > pathVariableNode </p>
- *
- * @param segment path segment
- * @param node node
- * @param selectorId selectorId
- * @return {@linkplain ShenyuTrieNode}
- */
- private ShenyuTrieNode matchNode(final String segment, final
ShenyuTrieNode node, final String selectorId,
- final Boolean endOfPath, final String
lastSegment) {
- if (Objects.nonNull(node)) {
- // node exist in children,first find path, avoid A plug have
/http/**, B plug have /http/order/**
- if (checkChildrenNotNull(node)) {
- Pair<Boolean, ShenyuTrieNode> pair = filterTrieNode(node,
selectorId, endOfPath, lastSegment);
- if (pair.getLeft()) {
- return pair.getRight();
+ int startIndex = 0;
+ ShenyuTrieNode currentNode = root;
+ int[] matchAll = new int[pathParts.length];
+ int[] wildcard = new int[pathParts.length];
+ int[] pathVariable = new int[pathParts.length];
+ while (startIndex < pathParts.length) {
+ String key = pathParts[startIndex];
+ boolean endPath = judgeEqual(startIndex, pathParts.length - 1);
+ if (Objects.isNull(currentNode)) {
+ return null;
+ }
+ if (containsKey(currentNode.getChildren(), key)) {
+ currentNode = getVal(currentNode.getChildren(), key);
+ startIndex++;
+ if (!endPath && Objects.nonNull(currentNode) &&
!currentNode.getEndOfPath()) {
+ continue;
+ }
+ } else if (containsKey(currentNode.getChildren(), WILDCARD) &&
wildcard[startIndex] == 0) {
+ checkAccess(wildcard, currentNode, startIndex, WILDCARD);
+ currentNode = getVal(currentNode.getChildren(), WILDCARD);
+ startIndex++;
+ if (Objects.nonNull(currentNode) && !endPath &&
!currentNode.getEndOfPath()) {
+ continue;
}
- if (containsKey(node.getChildren(), segment)) {
- return getVal(node.getChildren(), segment);
+ } else if (containsKey(currentNode.getChildren(), MATCH_ALL) &&
matchAll[startIndex] == 0) {
+ checkAccess(matchAll, currentNode, startIndex, MATCH_ALL);
+ currentNode = getVal(currentNode.getChildren(), MATCH_ALL);
+ startIndex++;
+ if (Objects.nonNull(currentNode) && !endPath &&
!currentNode.getEndOfPath()) {
+ continue;
}
- if (containsKey(node.getChildren(), WILDCARD)) {
- return getVal(node.getChildren(), WILDCARD);
+ } else if (Objects.nonNull(currentNode.getPathVariableNode())) {
+ if (pathVariable[startIndex] == 0 &&
Objects.nonNull(currentNode.getPathVariableNode())) {
+ pathVariable[startIndex] = 1;
}
- if (containsKey(node.getChildren(), MATCH_ALL)) {
- return getVal(node.getChildren(), MATCH_ALL);
+ currentNode = currentNode.getPathVariableNode();
+ startIndex++;
+ if (!endPath && !currentNode.getEndOfPath()) {
+ continue;
}
}
- // if node is path variable node
- if (Objects.nonNull(node.getPathVariableNode())) {
- return node.getPathVariableNode();
+ if (checkNode(endPath, currentNode, selectorId)) {
+ return currentNode;
+ }
+ // resolve conflict int mathAll, wildcard, pathVariable
+ if (startIndex >= pathParts.length - 1) {
+ Pair<Integer, ShenyuTrieNode> pair = resolveConflict(wildcard,
matchAll, pathVariable);
+ if (Objects.nonNull(pair)) {
+ startIndex = pair.getLeft();
+ currentNode = pair.getRight();
+ } else {
+ return null;
+ }
+ } else {
+ startIndex++;
}
}
return null;
@@ -329,7 +262,7 @@ public class ShenyuTrie {
// check current mapping
List<RuleData> ruleDataList =
getVal(currentNode.getPathRuleCache(), ruleData.getSelectorId());
ruleDataList =
Optional.ofNullable(ruleDataList).orElse(Collections.emptyList());
- synchronized (ruleData.getSelectorId()) {
+ synchronized (ruleData.getId()) {
ruleDataList.removeIf(rule ->
ruleData.getId().equals(rule.getId()));
}
if (CollectionUtils.isEmpty(ruleDataList) &&
Objects.isNull(currentNode.getChildren())
@@ -354,67 +287,152 @@ public class ShenyuTrie {
if (StringUtils.isNotBlank(uriPath)) {
String strippedPath = StringUtils.strip(uriPath, "/");
String[] pathParts = StringUtils.split(strippedPath, "/");
- if (pathParts.length > 0) {
- return getNode0(root, pathParts);
+ // get node from path pathParts
+ ShenyuTrieNode node = root;
+ for (int i = 0; i < pathParts.length; i++) {
+ String key = pathParts[i];
+ if (Objects.nonNull(node)) {
+ if (isPathVariable(key) &&
Objects.nonNull(node.getPathVariablesSet())) {
+ node = node.getPathVariablesSet().get(key);
+ } else {
+ node = getVal(node.getChildren(), key);
+ }
+ }
+ if (i == pathParts.length - 1) {
+ return node;
+ }
}
}
return null;
}
- private Pair<Boolean, ShenyuTrieNode> filterTrieNode(final ShenyuTrieNode
node, final String selectorId,
- final boolean
endOfPath, final String lastSegment) {
- Map<String, ShenyuTrieNode> currentMap = node.getChildren();
- List<ShenyuTrieNode> filterTrieNodes = currentMap.values().stream()
- .filter(currentNode -> currentNode.getEndOfPath() &&
selectorId.equals(currentNode.getSelectorId())
- && (isMatchAllOrWildcard(currentNode.getMatchStr()) ||
(endOfPath && lastSegment.equals(currentNode.getMatchStr()))))
- .collect(Collectors.toList());
- if (filterTrieNodes.size() != 1) {
- return Pair.of(Boolean.FALSE, null);
- } else {
- return Pair.of(Boolean.TRUE,
filterTrieNodes.stream().findFirst().orElse(null));
+ /**
+ * check legal path.
+ *
+ * @param pathParts path array
+ */
+ private void checkLegalPath(final String uriPath, final String[]
pathParts) {
+ //int position = Arrays.binarySearch(pathParts, 0, pathParts.length,
MATCH_ALL);
+ for (int i = 0; i < pathParts.length; i++) {
+ if (!judgeEqual(i, pathParts.length - 1) &&
isMatchAll(pathParts[i])) {
+ LOG.error("error path:{}, error position:{}", uriPath, i);
+ throw new ShenyuException("No more pattern data allowed after
** pattern element");
+ }
}
}
-
+
/**
- * get node.
+ * put node to trie.
*
- * @param node node
- * @param pathParts path parts
+ * @param segment current string
+ * @param shenyuTrieNode current trie node
+ * @param pathEnd end path
* @return {@linkplain ShenyuTrieNode}
*/
- private ShenyuTrieNode getNode0(final ShenyuTrieNode node, final String[]
pathParts) {
- // get key in path part arrays
- String key = pathParts[0];
- String[] slice = Arrays.copyOfRange(pathParts, 1, pathParts.length);
- // if exist one path
- if (slice.length == 0) {
- if (isMatchAllOrWildcard(key)) {
- return getVal(node.getChildren(), key);
- } else if (isPathVariable(key)) {
- if (Objects.nonNull(node) &&
node.getPathVariableNode().getEndOfPath()) {
- return node.getPathVariableNode();
- }
+ private ShenyuTrieNode putNode0(final String segment, final ShenyuTrieNode
shenyuTrieNode, final boolean pathEnd) {
+ // if match mode is path pattern, when segment is * and **, return
current node
+ if (TrieMatchModeEnum.PATH_PATTERN.getMatchMode().equals(matchMode)) {
+ if (isMatchAll(segment)) {
+ // put node, and return node
+ return this.put(segment, shenyuTrieNode, pathEnd);
+ }
+ if (isMatchWildcard(segment)) {
+ ShenyuTrieNode wildcardNode = this.put(segment,
shenyuTrieNode, pathEnd);
+ wildcardNode.setWildcard(true);
+ return wildcardNode;
+ }
+ }
+ if (TrieMatchModeEnum.ANT_PATH_MATCH.getMatchMode().equals(matchMode))
{
+ if (isMatchAll(segment) && pathEnd) {
+ return this.put(segment, shenyuTrieNode, true);
+ }
+ if (isMatchWildcard(segment) && pathEnd) {
+ ShenyuTrieNode wildcardNode = this.put(segment,
shenyuTrieNode, true);
+ wildcardNode.setWildcard(true);
+ return wildcardNode;
+ }
+ }
+ // dynamic route
+ if (isPathVariable(segment)) {
+ ShenyuTrieNode childNode;
+ // contains key, get current pathVariable node
+ if (containsKey(shenyuTrieNode.getPathVariablesSet(), segment)) {
+ childNode = getVal(shenyuTrieNode.getPathVariablesSet(),
segment);
} else {
- if (Objects.nonNull(node) && checkChildrenNotNull(node)) {
- return getVal(node.getChildren(), key);
+ childNode = new ShenyuTrieNode();
+ childNode.setMatchStr(segment);
+ childNode.setEndOfPath(pathEnd);
+ if (Objects.isNull(shenyuTrieNode.getPathVariablesSet())) {
+ shenyuTrieNode.setPathVariablesSet(new
WindowTinyLFUMap<>(pathVariableSize));
}
+ shenyuTrieNode.getPathVariablesSet().put(segment, childNode);
+ shenyuTrieNode.setPathVariableNode(childNode);
}
- return null;
+ return childNode;
+ }
+ return this.put(segment, shenyuTrieNode, pathEnd);
+ }
+
+ /**
+ * put node.
+ *
+ * @param segment segment
+ * @param shenyuTrieNode shenyu trie node
+ * @param pathEnd end of path
+ * @return ShenyuTrieNode
+ */
+ private ShenyuTrieNode put(final String segment, final ShenyuTrieNode
shenyuTrieNode, final boolean pathEnd) {
+ if (Objects.isNull(shenyuTrieNode.getChildren())) {
+ shenyuTrieNode.setChildren(new WindowTinyLFUMap<>(childrenSize));
+ }
+ ShenyuTrieNode childrenNode;
+ if (containsKey(shenyuTrieNode.getChildren(), segment)) {
+ childrenNode = getVal(shenyuTrieNode.getChildren(), segment);
} else {
- if (isPathVariable(key)) {
- if (Objects.isNull(node.getPathVariableNode())) {
- return null;
- }
- return this.getNode0(node.getPathVariableNode(), slice);
- } else {
- if (Objects.isNull(node) || Objects.isNull(node.getChildren())
|| Objects.isNull(getVal(node.getChildren(), key))) {
- return null;
- } else {
- return this.getNode0(getVal(node.getChildren(), key),
slice);
- }
+ childrenNode = new ShenyuTrieNode();
+ childrenNode.setMatchStr(segment);
+ childrenNode.setEndOfPath(pathEnd);
+ shenyuTrieNode.getChildren().put(segment, childrenNode);
+ }
+ return childrenNode;
+ }
+
+ private void checkAccess(final int[] arr, final ShenyuTrieNode node, final
int startIndex, final String key) {
+ if (WILDCARD.equals(key)) {
+ if (arr[startIndex] == 0 && containsKey(node.getChildren(),
WILDCARD)) {
+ arr[startIndex] = 1;
+ }
+ }
+ if (MATCH_ALL.equals(key)) {
+ if (arr[startIndex] == 0 && containsKey(node.getChildren(),
MATCH_ALL)) {
+ arr[startIndex] = 1;
}
}
}
+
+ private boolean checkNode(final boolean endPath, final ShenyuTrieNode
currentNode, final String selectorId) {
+ return endPath && Objects.nonNull(currentNode) &&
currentNode.getEndOfPath()
+ && selectorId.equals(currentNode.getSelectorId()) &&
Objects.nonNull(currentNode.getPathRuleCache())
+ &&
CollectionUtils.isNotEmpty(currentNode.getPathRuleCache().get(selectorId));
+ }
+
+ private Pair<Integer, ShenyuTrieNode> resolveConflict(final int[]
wildcard, final int[] matchAll, final int[] pathVariable) {
+ BitSet wildcardSet = ArrayUtils.indexesOf(wildcard, 1);
+ BitSet matchAllSet = ArrayUtils.indexesOf(matchAll, 1);
+ BitSet pathVariableSet = ArrayUtils.indexesOf(pathVariable, 1);
+ if (!wildcardSet.isEmpty()) {
+ wildcard[wildcardSet.nextSetBit(0)] = -1;
+ return Pair.of(0, root);
+ } else if (!matchAllSet.isEmpty()) {
+ matchAll[matchAllSet.nextSetBit(0)] = -1;
+ return Pair.of(0, root);
+ } else if (!pathVariableSet.isEmpty()) {
+ pathVariable[pathVariableSet.nextSetBit(0)] = -1;
+ return Pair.of(0, root);
+ } else {
+ return null;
+ }
+ }
/**
* get current node biz info.
diff --git
a/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/AbstractShenyuPluginTest.java
b/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/AbstractShenyuPluginTest.java
index c2b450713..c96581a89 100644
---
a/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/AbstractShenyuPluginTest.java
+++
b/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/AbstractShenyuPluginTest.java
@@ -23,7 +23,7 @@ import org.apache.shenyu.common.dto.PluginData;
import org.apache.shenyu.common.dto.RuleData;
import org.apache.shenyu.common.dto.SelectorData;
import org.apache.shenyu.common.enums.SelectorTypeEnum;
-import org.apache.shenyu.common.enums.TrieMatchModeEvent;
+import org.apache.shenyu.common.enums.TrieMatchModeEnum;
import org.apache.shenyu.plugin.api.ShenyuPluginChain;
import org.apache.shenyu.plugin.api.utils.SpringBeanUtils;
import org.apache.shenyu.plugin.base.cache.BaseDataCache;
@@ -247,7 +247,7 @@ public final class AbstractShenyuPluginTest {
private void mockShenyuConfig() {
ConfigurableApplicationContext context =
mock(ConfigurableApplicationContext.class);
when(context.getBean(ShenyuConfig.class)).thenReturn(new
ShenyuConfig());
- when(context.getBean(ShenyuTrie.class)).thenReturn(new
ShenyuTrie(100L, 100L, 100L, TrieMatchModeEvent.ANT_PATH_MATCH.getMatchMode()));
+ when(context.getBean(ShenyuTrie.class)).thenReturn(new
ShenyuTrie(100L, 100L, 100L, TrieMatchModeEnum.ANT_PATH_MATCH.getMatchMode()));
SpringBeanUtils.getInstance().setApplicationContext(context);
}
diff --git
a/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriberTest.java
b/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriberTest.java
index 986966358..88b80bbd3 100644
---
a/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriberTest.java
+++
b/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriberTest.java
@@ -18,10 +18,11 @@
package org.apache.shenyu.plugin.base.cache;
import com.google.common.collect.Lists;
+import org.apache.shenyu.common.config.ShenyuConfig.ShenyuTrieConfig;
import org.apache.shenyu.common.dto.PluginData;
import org.apache.shenyu.common.dto.RuleData;
import org.apache.shenyu.common.dto.SelectorData;
-import org.apache.shenyu.common.enums.TrieMatchModeEvent;
+import org.apache.shenyu.common.enums.TrieMatchModeEnum;
import org.apache.shenyu.plugin.api.utils.SpringBeanUtils;
import org.apache.shenyu.plugin.base.handler.PluginDataHandler;
import org.apache.shenyu.plugin.base.trie.ShenyuTrie;
@@ -74,7 +75,7 @@ public final class CommonPluginDataSubscriberTest {
public void setup() {
this.mockShenyuTrieConfig();
ArrayList<PluginDataHandler> pluginDataHandlerList =
Lists.newArrayList();
- commonPluginDataSubscriber = new
CommonPluginDataSubscriber(pluginDataHandlerList, eventPublisher);
+ commonPluginDataSubscriber = new
CommonPluginDataSubscriber(pluginDataHandlerList, eventPublisher, new
ShenyuTrieConfig());
baseDataCache = BaseDataCache.getInstance();
}
@@ -233,7 +234,7 @@ public final class CommonPluginDataSubscriberTest {
private void mockShenyuTrieConfig() {
ConfigurableApplicationContext context =
mock(ConfigurableApplicationContext.class);
- when(context.getBean(ShenyuTrie.class)).thenReturn(new
ShenyuTrie(100L, 100L, 100L, TrieMatchModeEvent.ANT_PATH_MATCH.getMatchMode()));
+ when(context.getBean(ShenyuTrie.class)).thenReturn(new
ShenyuTrie(100L, 100L, 100L, TrieMatchModeEnum.ANT_PATH_MATCH.getMatchMode()));
SpringBeanUtils.getInstance().setApplicationContext(context);
}
}
diff --git
a/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/trie/ShenyuTrieTest.java
b/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/trie/ShenyuTrieTest.java
index a64c53fbf..da4dab19c 100644
---
a/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/trie/ShenyuTrieTest.java
+++
b/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/trie/ShenyuTrieTest.java
@@ -21,9 +21,9 @@ import org.apache.shenyu.common.dto.ConditionData;
import org.apache.shenyu.common.dto.RuleData;
import org.apache.shenyu.common.enums.OperatorEnum;
import org.apache.shenyu.common.enums.ParamTypeEnum;
-import org.apache.shenyu.common.enums.TrieMatchModeEvent;
+import org.apache.shenyu.common.enums.TrieMatchModeEnum;
+import org.apache.shenyu.common.exception.ShenyuException;
import org.apache.shenyu.plugin.api.utils.SpringBeanUtils;
-import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -35,27 +35,35 @@ import java.util.Collections;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-class ShenyuTrieTest {
+public class ShenyuTrieTest {
- private ShenyuTrie shenyuTrie;
+ private ShenyuTrie shenyuAntPathTrie;
+
+ private ShenyuTrie shenyuPathPatternTrie;
@BeforeEach
public void mockAntPathShenyuTrie() {
ConfigurableApplicationContext context =
mock(ConfigurableApplicationContext.class);
- when(context.getBean(ShenyuTrie.class)).thenReturn(new
ShenyuTrie(100L, 100L, 100L, TrieMatchModeEvent.ANT_PATH_MATCH.getMatchMode()));
+ when(context.getBean(ShenyuTrie.class)).thenReturn(new
ShenyuTrie(100L, 100L, 100L, TrieMatchModeEnum.ANT_PATH_MATCH.getMatchMode()));
+ SpringBeanUtils.getInstance().setApplicationContext(context);
+ shenyuAntPathTrie =
SpringBeanUtils.getInstance().getBean(ShenyuTrie.class);
+
+ when(context.getBean(ShenyuTrie.class)).thenReturn(new
ShenyuTrie(100L, 100L, 100L, TrieMatchModeEnum.PATH_PATTERN.getMatchMode()));
SpringBeanUtils.getInstance().setApplicationContext(context);
- shenyuTrie = SpringBeanUtils.getInstance().getBean(ShenyuTrie.class);
+ shenyuPathPatternTrie =
SpringBeanUtils.getInstance().getBean(ShenyuTrie.class);
}
- @AfterEach
+ @Test
public void clear() {
- shenyuTrie.clear();
- Assertions.assertTrue(shenyuTrie.isEmpty());
+ shenyuAntPathTrie.clear();
+ shenyuPathPatternTrie.clear();
+ Assertions.assertTrue(shenyuAntPathTrie.isEmpty());
+ Assertions.assertTrue(shenyuPathPatternTrie.isEmpty());
}
@Test
public void putNode() {
- final String uri = "/a/b/c/**";
+ final String uri = "/a/b/c/**/*/cc";
ConditionData conditionData = new ConditionData();
conditionData.setParamType(ParamTypeEnum.URI.getName());
conditionData.setOperator(OperatorEnum.MATCH.getAlias());
@@ -69,8 +77,35 @@ class ShenyuTrieTest {
.enabled(true)
.conditionDataList(Collections.singletonList(conditionData))
.build();
- shenyuTrie.putNode(uri, ruleData, null);
- Assertions.assertNotNull(shenyuTrie.getNode(uri));
+ shenyuAntPathTrie.putNode(uri, ruleData, null);
+ Assertions.assertNotNull(shenyuAntPathTrie.getNode(uri));
+ Assertions.assertThrows(ShenyuException.class, () ->
shenyuPathPatternTrie.putNode("/aa/bb/**/cc", ruleData, null));
+ shenyuPathPatternTrie.putNode("/aa/bb/cc/*/*/ee", ruleData, null);
+
Assertions.assertNotNull(shenyuPathPatternTrie.getNode("/aa/bb/cc/*/*/ee"));
+ }
+
+ @Test
+ public void pathPatternMatch() {
+ ConditionData conditionData = new ConditionData();
+ conditionData.setParamType(ParamTypeEnum.URI.getName());
+ conditionData.setOperator(OperatorEnum.MATCH.getAlias());
+ conditionData.setParamName("/");
+ conditionData.setParamValue("/a/b/c/**");
+ RuleData ruleData = RuleData.builder()
+ .id("1")
+ .pluginName("test")
+ .selectorId("1")
+ .name("test-plugin-rule")
+ .enabled(true)
+ .conditionDataList(Collections.singletonList(conditionData))
+ .build();
+ shenyuPathPatternTrie.putNode("/aa/bb/cc/{name}/{age}/tt", ruleData,
null);
+ shenyuPathPatternTrie.putNode("/aa/bb/cc/*/*/ii", ruleData, null);
+ shenyuPathPatternTrie.putNode("/aa/bb/cc/**", ruleData, null);
+
Assertions.assertNotNull(shenyuPathPatternTrie.match("/aa/bb/cc/hh/dd/ee/hh",
"1"));
+
Assertions.assertNotNull(shenyuPathPatternTrie.match("/aa/bb/cc/hh/dd/ee/tt",
"1"));
+
Assertions.assertNotNull(shenyuPathPatternTrie.match("/aa/bb/cc/xx/yy/ii",
"1"));
+
Assertions.assertNull(shenyuPathPatternTrie.match("/aa/bb/mm/yyy/hhhl", "1"));
}
@Test
@@ -88,8 +123,12 @@ class ShenyuTrieTest {
.enabled(true)
.conditionDataList(Collections.singletonList(conditionData))
.build();
- shenyuTrie.putNode("/a/b/c/**", ruleData, null);
- Assertions.assertNotNull(shenyuTrie.match("/a/b/c/d/e/f", "1"));
+
+ shenyuAntPathTrie.putNode("/aa/**/*.html", ruleData, null);
+ shenyuAntPathTrie.putNode("/a/b/c/**", ruleData, null);
+ Assertions.assertNotNull(shenyuAntPathTrie.match("/a/b/c/d/e/f", "1"));
+
+ shenyuAntPathTrie.putNode("/a/b/**/c", ruleData, null);
RuleData ruleData2 = RuleData.builder()
.id("2")
@@ -99,17 +138,26 @@ class ShenyuTrieTest {
.enabled(true)
.conditionDataList(Collections.singletonList(conditionData))
.build();
- shenyuTrie.putNode("/a/*/b/c", ruleData2, null);
- Assertions.assertNull(shenyuTrie.match("/a/m/b/c", "1"));
- Assertions.assertNotNull(shenyuTrie.match("/a/m/b/c", "2"));
+ shenyuAntPathTrie.putNode("/a/*/b/c", ruleData2, null);
+ Assertions.assertNull(shenyuAntPathTrie.match("/a/m/b/c", "1"));
+ Assertions.assertNotNull(shenyuAntPathTrie.match("/a/m/b/c", "2"));
+
+ shenyuAntPathTrie.putNode("/path1/{name}/{age}", ruleData, null);
+ Assertions.assertNotNull(shenyuAntPathTrie.match("/path1/111/222",
"1").getFullPath(), "/path1/{name}/{age}");
+ Assertions.assertNull(shenyuAntPathTrie.match("/path1/111/222/333",
"1"));
- shenyuTrie.putNode("/path1/{name}/{age}", ruleData, null);
- Assertions.assertNotNull(shenyuTrie.match("/path1/111/222",
"1").getFullPath(), "/path1/{name}/{age}");
- Assertions.assertNull(shenyuTrie.match("/path1/111/222/333", "1"));
+ shenyuAntPathTrie.putNode("path1/name/age", ruleData, null);
+ Assertions.assertNotNull(shenyuAntPathTrie.match("path1/name/age",
"1"));
+ Assertions.assertEquals(shenyuAntPathTrie.match("path1/name/age",
"1").getFullPath(), "path1/name/age");
- shenyuTrie.putNode("path1/name/age", ruleData, null);
- Assertions.assertNotNull(shenyuTrie.match("path1/name/age", "1"));
- Assertions.assertEquals(shenyuTrie.match("path1/name/age",
"1").getFullPath(), "path1/name/age");
+ shenyuAntPathTrie.putNode("/aa/bb/cc/{name}/{age}/tt", ruleData, null);
+ shenyuAntPathTrie.putNode("/aa/bb/cc/*/*/ii", ruleData, null);
+ shenyuAntPathTrie.putNode("/aa/bb/cc/**/hh", ruleData, null);
+ Assertions.assertNotNull(shenyuAntPathTrie.match("/aa/bb/cc/dd/ee/tt",
"1"));
+ Assertions.assertNotNull(shenyuAntPathTrie.match("/aa/bb/cc/dd/ee/hh",
"1"));
+ Assertions.assertNotNull(shenyuAntPathTrie.match("/aa/bb/cc/dd/ee/ii",
"1"));
+
Assertions.assertNotNull(shenyuAntPathTrie.match("/aa/bb/cc/dd/rr/mm/ee/hh",
"1"));
+
Assertions.assertNull(shenyuAntPathTrie.match("/aa/bb/cc/dd/rr/mm/ee/yy", "1"));
}
@Test
@@ -150,13 +198,13 @@ class ShenyuTrieTest {
.enabled(true)
.conditionDataList(Arrays.asList(conditionData,
conditionData1, conditionData2, conditionData3))
.build();
- shenyuTrie.putNode(Arrays.asList(uriPath, uriPath1, uriPath2,
uriPath3), ruleData, null);
+ shenyuAntPathTrie.putNode(Arrays.asList(uriPath, uriPath1, uriPath2,
uriPath3), ruleData, null);
- Assertions.assertEquals(shenyuTrie.match("/a/b/c/d/e/f",
"1").getFullPath(), uriPath);
- Assertions.assertEquals(shenyuTrie.match("/a/g/c/e/ef/hi",
"1").getFullPath(), uriPath1);
- Assertions.assertEquals(shenyuTrie.match("/a/g/hi/def",
"1").getFullPath(), uriPath2);
- Assertions.assertEquals(shenyuTrie.match("/a/gh/ij/klm",
"1").getFullPath(), uriPath2);
- Assertions.assertNotEquals(shenyuTrie.match("/a/egh/fij/klm",
"1").getFullPath(), uriPath3);
+ Assertions.assertEquals(shenyuAntPathTrie.match("/a/b/c/d/e/f",
"1").getFullPath(), uriPath);
+ Assertions.assertEquals(shenyuAntPathTrie.match("/a/g/c/e/ef/hi",
"1").getFullPath(), uriPath1);
+ Assertions.assertEquals(shenyuAntPathTrie.match("/a/g/hi/def",
"1").getFullPath(), uriPath2);
+ Assertions.assertEquals(shenyuAntPathTrie.match("/a/gh/ij/klm",
"1").getFullPath(), uriPath2);
+ Assertions.assertNotEquals(shenyuAntPathTrie.match("/a/egh/fij/klm",
"1").getFullPath(), uriPath3);
}
@Test
@@ -184,10 +232,12 @@ class ShenyuTrieTest {
.sort(2)
.conditionDataList(Collections.singletonList(conditionData))
.build();
- shenyuTrie.putNode("/a/b/c/**", ruleData, null);
- shenyuTrie.putNode("/a/b/c/**", ruleData2, null);
- shenyuTrie.remove("/a/b/c/**", ruleData2);
- Assertions.assertNotNull(shenyuTrie.getNode("/a/b/c/**"));
+ shenyuAntPathTrie.putNode("/a/b/c/**", ruleData, null);
+ shenyuAntPathTrie.putNode("/a/b/c/**", ruleData2, null);
+ shenyuAntPathTrie.remove("/a/b/c/**", ruleData2);
+ Assertions.assertNotNull(shenyuAntPathTrie.getNode("/a/b/c/**"));
+ shenyuAntPathTrie.remove("/a/b/c/**", ruleData);
+ Assertions.assertNull(shenyuAntPathTrie.getNode("/a/b/c/**"));
RuleData ruleData3 = RuleData.builder()
.id("3")
@@ -198,9 +248,9 @@ class ShenyuTrieTest {
.sort(2)
.conditionDataList(Collections.singletonList(conditionData))
.build();
- shenyuTrie.putNode("/path1/path2", ruleData3, null);
- shenyuTrie.remove("/path1/path2", ruleData3);
- Assertions.assertNull(shenyuTrie.getNode("/path1/path2"));
+ shenyuAntPathTrie.putNode("/path1/path2", ruleData3, null);
+ shenyuAntPathTrie.remove("/path1/path2", ruleData3);
+ Assertions.assertNull(shenyuAntPathTrie.getNode("/path1/path2"));
}
@Test
@@ -228,15 +278,18 @@ class ShenyuTrieTest {
.sort(2)
.conditionDataList(Collections.singletonList(conditionData))
.build();
- shenyuTrie.putNode("/a/b/c/**", ruleData, null);
- shenyuTrie.putNode("/a/b/c/**", ruleData2, null);
- Assertions.assertNotNull(shenyuTrie.getNode("/a/b/c/**"));
- shenyuTrie.putNode("/path1/{age}/{name}", ruleData2, null);
- Assertions.assertNotNull(shenyuTrie.getNode("/path1/{age}/{name}"));
- shenyuTrie.putNode("/aaa/bbb/ccc", ruleData2, null);
- Assertions.assertNotNull(shenyuTrie.getNode("/aaa/bbb/ccc"));
- shenyuTrie.putNode("/aa/*/cc", ruleData2, null);
- Assertions.assertNotNull(shenyuTrie.getNode("/aa/*/cc"));
+ shenyuAntPathTrie.putNode("/a/b/c/**", ruleData, null);
+ shenyuAntPathTrie.putNode("/a/b/c/**", ruleData2, null);
+ Assertions.assertNotNull(shenyuAntPathTrie.getNode("/a/b/c/**"));
+ shenyuAntPathTrie.putNode("/path1/{age}/{name}", ruleData2, null);
+
Assertions.assertNotNull(shenyuAntPathTrie.getNode("/path1/{age}/{name}"));
+ shenyuAntPathTrie.putNode("/aaa/bbb/ccc", ruleData2, null);
+ Assertions.assertNotNull(shenyuAntPathTrie.getNode("/aaa/bbb/ccc"));
+ shenyuAntPathTrie.putNode("/aa/*/cc", ruleData2, null);
+ Assertions.assertNotNull(shenyuAntPathTrie.getNode("/aa/*/cc"));
+ shenyuAntPathTrie.putNode("/a/x/{name}/{age}/b", ruleData2, null);
+ shenyuAntPathTrie.putNode("/a/x/{name}/{sex}/c", ruleData2, null);
+
Assertions.assertNotNull(shenyuAntPathTrie.getNode("/a/x/{name}/{age}/b"));
}
}
diff --git
a/shenyu-spring-boot-starter/shenyu-spring-boot-starter-gateway/src/main/java/org/apache/shenyu/springboot/starter/gateway/ShenyuConfiguration.java
b/shenyu-spring-boot-starter/shenyu-spring-boot-starter-gateway/src/main/java/org/apache/shenyu/springboot/starter/gateway/ShenyuConfiguration.java
index 661da790f..89bd4920e 100644
---
a/shenyu-spring-boot-starter/shenyu-spring-boot-starter-gateway/src/main/java/org/apache/shenyu/springboot/starter/gateway/ShenyuConfiguration.java
+++
b/shenyu-spring-boot-starter/shenyu-spring-boot-starter-gateway/src/main/java/org/apache/shenyu/springboot/starter/gateway/ShenyuConfiguration.java
@@ -121,12 +121,15 @@ public class ShenyuConfiguration {
*
* @param pluginDataHandlerList the plugin data handler list
* @param eventPublisher event publisher
+ * @param shenyuConfig shenyu config
* @return the plugin data subscriber
*/
@Bean
public PluginDataSubscriber pluginDataSubscriber(final
ObjectProvider<List<PluginDataHandler>> pluginDataHandlerList,
- final
ObjectProvider<ApplicationEventPublisher> eventPublisher) {
- return new
CommonPluginDataSubscriber(pluginDataHandlerList.getIfAvailable(Collections::emptyList),
eventPublisher.getIfAvailable());
+ final
ObjectProvider<ApplicationEventPublisher> eventPublisher,
+ final ShenyuConfig
shenyuConfig) {
+ return new
CommonPluginDataSubscriber(pluginDataHandlerList.getIfAvailable(Collections::emptyList),
+ eventPublisher.getIfAvailable(), shenyuConfig.getTrie());
}
/**
diff --git
a/shenyu-web/src/test/java/org/apache/shenyu/web/controller/LocalPluginControllerTest.java
b/shenyu-web/src/test/java/org/apache/shenyu/web/controller/LocalPluginControllerTest.java
index 3c5cbc01a..11e9de9b0 100644
---
a/shenyu-web/src/test/java/org/apache/shenyu/web/controller/LocalPluginControllerTest.java
+++
b/shenyu-web/src/test/java/org/apache/shenyu/web/controller/LocalPluginControllerTest.java
@@ -19,6 +19,7 @@ package org.apache.shenyu.web.controller;
import com.google.common.collect.Lists;
import com.google.common.reflect.TypeToken;
+import org.apache.shenyu.common.config.ShenyuConfig.ShenyuTrieConfig;
import org.apache.shenyu.common.dto.ConditionData;
import org.apache.shenyu.common.dto.PluginData;
import org.apache.shenyu.common.dto.RuleData;
@@ -29,7 +30,7 @@ import org.apache.shenyu.common.enums.LoadBalanceEnum;
import org.apache.shenyu.common.enums.OperatorEnum;
import org.apache.shenyu.common.enums.ParamTypeEnum;
import org.apache.shenyu.common.enums.PluginEnum;
-import org.apache.shenyu.common.enums.TrieMatchModeEvent;
+import org.apache.shenyu.common.enums.TrieMatchModeEnum;
import org.apache.shenyu.common.utils.GsonUtils;
import org.apache.shenyu.common.utils.JsonUtils;
import org.apache.shenyu.plugin.api.utils.SpringBeanUtils;
@@ -91,7 +92,7 @@ public final class LocalPluginControllerTest {
public void setup() {
this.mockShenyuTrieConfig();
ArrayList<PluginDataHandler> pluginDataHandlerList =
Lists.newArrayList();
- subscriber = new CommonPluginDataSubscriber(pluginDataHandlerList,
eventPublisher);
+ subscriber = new CommonPluginDataSubscriber(pluginDataHandlerList,
eventPublisher, new ShenyuTrieConfig());
mockMvc = MockMvcBuilders.standaloneSetup(new
LocalPluginController(subscriber))
.build();
baseDataCache = BaseDataCache.getInstance();
@@ -491,7 +492,7 @@ public final class LocalPluginControllerTest {
private void mockShenyuTrieConfig() {
ConfigurableApplicationContext context =
mock(ConfigurableApplicationContext.class);
- when(context.getBean(ShenyuTrie.class)).thenReturn(new
ShenyuTrie(100L, 100L, 100L, TrieMatchModeEvent.ANT_PATH_MATCH.getMatchMode()));
+ when(context.getBean(ShenyuTrie.class)).thenReturn(new
ShenyuTrie(100L, 100L, 100L, TrieMatchModeEnum.ANT_PATH_MATCH.getMatchMode()));
SpringBeanUtils.getInstance().setApplicationContext(context);
}
}