private String findUnmatchedTimerStarts()

in src/main/java/org/apache/sling/engine/impl/SlingJakartaHttpServletResponseImpl.java [390:435]


    private String findUnmatchedTimerStarts() {
        Iterator<String> messages = getLastMessagesOfProgressTracker().iterator();
        List<String> unmatchedStarts = new ArrayList<>();
        Deque<String> timerDeque = new ArrayDeque<>();

        Pattern startPattern = Pattern.compile(REGEX_TIMER_START);
        Pattern endPattern = Pattern.compile(REGEX_TIMER_END);

        while (messages.hasNext()) {
            String message = messages.next();
            Matcher startMatcher = startPattern.matcher(message);
            Matcher endMatcher = endPattern.matcher(message);

            // use a Deque to keep track of the timers that have been started. When
            // an end timer is found, it is compared to the top of the deque. If they match,
            // the timer is removed from the deque. If they don't match, the timer is added
            // to the list of unmatched starts. As the deque is a LIFO data structure, the
            // last timer that was started will be the first one to be ended. There is no
            // Start1, Start2, End1 scenario, without an End2 in between.
            if (startMatcher.find()) {
                timerDeque.push(startMatcher.group(1));
            } else if (endMatcher.find()) {
                String endTimer = endMatcher.group(1);
                if (!timerDeque.isEmpty() && timerDeque.peek().equals(endTimer)) {
                    timerDeque.pop();
                } else {
                    unmatchedStarts.add(endTimer);
                }
            }
        }

        // ignore the first element, as it will never have a matching end, as it is the
        // first timer started and is not finished processing
        while (timerDeque.size() > 1) {
            unmatchedStarts.add(timerDeque.pop());
        }
        StringBuilder sb = new StringBuilder();
        for (String script : unmatchedStarts) {
            sb.append(script).append(TIMER_SEPARATOR);
        }
        String ret = sb.toString();
        if (ret.endsWith(TIMER_SEPARATOR)) {
            ret = ret.substring(0, ret.length() - TIMER_SEPARATOR.length());
        }
        return ret;
    }