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