in shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/trie/ShenyuTrie.java [184:262]
private void buildFailToNode(final ShenyuTrieNode root) {
if (Objects.isNull(root)) {
return;
}
Queue<ShenyuTrieNode> queue = new LinkedList<>();
Map<String, ShenyuTrieNode> pathVariableChildren = Optional.ofNullable(root.getPathVariables()).orElse(new HashMap<>(0));
Map<String, ShenyuTrieNode> children = Optional.ofNullable(root.getChildren()).orElse(new HashMap<>(0));
Map<String, ShenyuTrieNode> allChildren = new HashMap<>();
allChildren.putAll(children);
allChildren.putAll(pathVariableChildren);
allChildren.forEach((key, currentNode) -> {
currentNode.setFailToNode(root);
queue.offer(currentNode);
});
while (!queue.isEmpty()) {
ShenyuTrieNode currentNode = queue.poll();
Map<String, ShenyuTrieNode> childrenList = Optional.ofNullable(currentNode.getChildren()).orElse(new HashMap<>(0));
Map<String, ShenyuTrieNode> pathList = Optional.ofNullable(currentNode.getPathVariables()).orElse(new HashMap<>(0));
Map<String, ShenyuTrieNode> newChildren = new HashMap<>();
newChildren.putAll(childrenList);
newChildren.putAll(pathList);
if (allChildren.containsKey(currentNode.getMatchStr())) {
newChildren.forEach((key, node) -> queue.offer(node));
continue;
}
ShenyuTrieNode parent = currentNode.getParentNode();
if (!isMatchWildcard(currentNode.getMatchStr()) && !isMatchAll(currentNode.getMatchStr()) && !isPathVariable(currentNode.getMatchStr())) {
if (containsKey(parent.getChildren(), WILDCARD)) {
currentNode.setFailToNode(parent.getChildren().get(WILDCARD));
} else if (containsKey(parent.getChildren(), MATCH_ALL)) {
currentNode.setFailToNode(parent.getChildren().get(MATCH_ALL));
} else if (Objects.nonNull(parent.getPathVariableNode())) {
currentNode.setFailToNode(parent.getPathVariableNode());
} else {
currentNode.setFailToNode(parent.getFailToNode());
}
} else if (isMatchWildcard(currentNode.getMatchStr())) {
if (containsKey(parent.getChildren(), MATCH_ALL)) {
currentNode.setFailToNode(parent.getChildren().get(MATCH_ALL));
} else if (Objects.nonNull(parent.getPathVariableNode())) {
currentNode.setFailToNode(parent.getPathVariableNode());
} else {
currentNode.setFailToNode(parent.getFailToNode());
}
} else if (isMatchAll(currentNode.getMatchStr())) {
if (currentNode.getEndOfPath()) {
currentNode.setFailToNode(null);
} else if (Objects.nonNull(parent.getPathVariableNode())) {
currentNode.setFailToNode(parent.getPathVariableNode());
} else {
currentNode.setFailToNode(parent.getFailToNode());
}
} else if (isPathVariable(currentNode.getMatchStr()) && MapUtils.isNotEmpty(parent.getPathVariables())) {
if (parent.getPathVariables().size() == 1) {
currentNode.setFailToNode(parent.getFailToNode());
} else {
if (Objects.isNull(currentNode.getFailToNode())) {
Queue<ShenyuTrieNode> pathVariableQueue = new LinkedList<>();
Map<String, ShenyuTrieNode> map = new HashMap<>(parent.getPathVariables());
map.remove(currentNode.getMatchStr());
map.values().forEach(pathVariableQueue::offer);
while (!pathVariableQueue.isEmpty()) {
ShenyuTrieNode pathVariableNode = pathVariableQueue.poll();
if (pathVariableQueue.size() > 1) {
currentNode.setFailToNode(pathVariableNode);
currentNode = pathVariableNode;
} else {
currentNode.setFailToNode(pathVariableNode);
pathVariableNode.setFailToNode(parent.getFailToNode());
}
}
}
}
} else {
currentNode.setFailToNode(parent.getFailToNode());
}
newChildren.forEach((key, value) -> queue.offer(value));
}
}