private void buildFailToNode()

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));
        }
    }