protected String parseStringValue(String strVal, Set<String> visitedPlaceholders) {
        StringBuffer buf = new StringBuffer(strVal);
        int startIndex = strVal.indexOf(DEFAULT_PLACEHOLDER_PREFIX);
        while (startIndex != -1) {
            int endIndex = findPlaceholderEndIndex(buf, startIndex);
            if (endIndex != -1) {
                String placeholder = buf.substring(startIndex + DEFAULT_PLACEHOLDER_PREFIX.length(), endIndex);
                if (!visitedPlaceholders.add(placeholder)) {
                    throw new SeataRuntimeException(ErrorCode.ERR_CONFIG,
                        "Duplicate placeholders exist '" + placeholder + "' in bundle.");
                }
                placeholder = parseStringValue(placeholder, visitedPlaceholders);
                try {
                    String propVal = resolvePlaceholder(placeholder);
                    if (propVal != null) {
                        propVal = parseStringValue(propVal, visitedPlaceholders);
                        buf.replace(startIndex, endIndex + DEFAULT_PLACEHOLDER_SUFFIX.length(), propVal);
                        startIndex = buf.indexOf(DEFAULT_PLACEHOLDER_PREFIX, startIndex + propVal.length());
                    } else {
                        throw new SeataRuntimeException(ErrorCode.ERR_CONFIG,
                            "Could not resolve placeholder '" + placeholder + "'");
                    }
                } catch (Exception ex) {
                    throw new SeataRuntimeException(ErrorCode.ERR_CONFIG,
                        "Could not resolve placeholder '" + placeholder + "'");
                }
                visitedPlaceholders.remove(placeholder);
            } else {
                startIndex = -1;
            }
        }

        return buf.toString();
    }
@Test
    void parseStringValue() {
        ResourceBundleUtil resourceBundleUtil = ResourceBundleUtil.getInstance();
        String strVal = "str val without placeholder";
        String parseValue = resourceBundleUtil.parseStringValue(strVal, new HashSet<>());
        Assertions.assertEquals(strVal, parseValue);
        strVal = "str val without placeholder ${";
        parseValue = resourceBundleUtil.parseStringValue(strVal, new HashSet<>());
        Assertions.assertEquals(strVal, parseValue);
        strVal = "str val without placeholder }";
        parseValue = resourceBundleUtil.parseStringValue(strVal, new HashSet<>());
        Assertions.assertEquals(strVal, parseValue);

        final String strValWithEmptyPlaceHolder = "str val with placeholder ${}";
        Assertions.assertThrows(SeataRuntimeException.class, new Executable() {
            @Override
            public void execute() throws Throwable {
                resourceBundleUtil.parseStringValue(strValWithEmptyPlaceHolder, new HashSet<>());
            }
        }, "Could not resolve placeholder 'str val with placeholder ${}'");
        String strValWithPlaceHolder = "str val with placeholder ${ERR_CONFIG}";
        Set<String> holderSet = new HashSet<>();
        parseValue = resourceBundleUtil.parseStringValue(strValWithPlaceHolder, holderSet);
        Assertions.assertEquals("str val with placeholder config error, {0}", parseValue);
        Assertions.assertEquals(0, holderSet.size());

        String multiSamePlaceHolder = "str val with placeholder ${ERR_CONFIG},${ERR_CONFIG}";
        parseValue = resourceBundleUtil.parseStringValue(multiSamePlaceHolder, holderSet);
        Assertions.assertEquals("str val with placeholder config error, {0},config error, {0}", parseValue);

        final String strValWithEmptyPlaceHolderValue = "str val with placeholder ${ERR_NOT_EXIST}";
        Assertions.assertDoesNotThrow(new Executable() {
            @Override
            public void execute() throws Throwable {
                Set<String> placeholderSet = new HashSet<>();
                resourceBundleUtil.parseStringValue(strValWithEmptyPlaceHolderValue, placeholderSet);
                Assertions.assertEquals(0, placeholderSet.size());
            }
        });

        final String strValWithNestPlaceHolderValue = "str val with placeholder ${${${ERROR_LOOP}}}";
        Set<String> placeholderSet = new HashSet<>();
        parseValue = resourceBundleUtil.parseStringValue(strValWithNestPlaceHolderValue, new HashSet<>());
        Assertions.assertEquals("str val with placeholder ERROR_LOOP", parseValue);
        Assertions.assertEquals(0, placeholderSet.size());

        String strValWithNestPlaceHolder = "str val with placeholder ${${ERR_NEST2}}";
        parseValue = resourceBundleUtil.parseStringValue(strValWithNestPlaceHolder, new HashSet<>());
        Assertions.assertEquals("str val with placeholder ERR NEST TEST", parseValue);
        Assertions.assertEquals(0, placeholderSet.size());
    }