Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add caching to o.s.b.test.system.OutputCapture #32180

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -23,6 +23,8 @@
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Predicate;

Expand All @@ -39,6 +41,7 @@
* @author Phillip Webb
* @author Andy Wilkinson
* @author Sam Brannen
* @author Pavel Anisimov
* @see OutputCaptureExtension
* @see OutputCaptureRule
*/
Expand All @@ -48,14 +51,16 @@ class OutputCapture implements CapturedOutput {

private AnsiOutputState ansiOutputState;

private final Map<Predicate<Type>, String> filter2CachedCapturedStrings = new ConcurrentHashMap<>();

/**
* Push a new system capture session onto the stack.
*/
final void push() {
if (this.systemCaptures.isEmpty()) {
this.ansiOutputState = AnsiOutputState.saveAndDisable();
}
this.systemCaptures.addLast(new SystemCapture());
this.systemCaptures.addLast(new SystemCapture(this));
}

/**
Expand Down Expand Up @@ -97,7 +102,7 @@ public String toString() {
*/
@Override
public String getAll() {
return get((type) -> true);
return get(Type.filterAll);
}

/**
Expand All @@ -106,7 +111,7 @@ public String getAll() {
*/
@Override
public String getOut() {
return get(Type.OUT::equals);
return get(Type.filterOut);
}

/**
Expand All @@ -115,7 +120,7 @@ public String getOut() {
*/
@Override
public String getErr() {
return get(Type.ERR::equals);
return get(Type.filterErr);
}

/**
Expand All @@ -128,15 +133,21 @@ void reset() {
private String get(Predicate<Type> filter) {
Assert.state(!this.systemCaptures.isEmpty(),
"No system captures found. Please check your output capture registration.");
String cachedCapturedStrings = this.filter2CachedCapturedStrings.get(filter);
if (cachedCapturedStrings != null) {
return cachedCapturedStrings;
}
StringBuilder builder = new StringBuilder();
for (SystemCapture systemCapture : this.systemCaptures) {
systemCapture.append(builder, filter);
}
return builder.toString();
String capturedStrings = builder.toString();
this.filter2CachedCapturedStrings.put(filter, capturedStrings);
return capturedStrings;
}

/**
* A capture session that captures {@link System#out System.out} and {@link System#out
* A capture session that captures {@link System#out System.out} and {@link System#err
* System.err}.
*/
private static class SystemCapture {
Expand All @@ -149,26 +160,34 @@ private static class SystemCapture {

private final List<CapturedString> capturedStrings = new ArrayList<>();

SystemCapture() {
private final OutputCapture owner;

SystemCapture(OutputCapture owner) {
this.out = new PrintStreamCapture(System.out, this::captureOut);
this.err = new PrintStreamCapture(System.err, this::captureErr);
this.owner = owner;
System.setOut(this.out);
System.setErr(this.err);
}

void release() {
this.owner.filter2CachedCapturedStrings.clear();
System.setOut(this.out.getParent());
System.setErr(this.err.getParent());
}

private void captureOut(String string) {
synchronized (this.monitor) {
this.owner.filter2CachedCapturedStrings.remove(Type.filterOut);
this.owner.filter2CachedCapturedStrings.remove(Type.filterAll);
this.capturedStrings.add(new CapturedString(Type.OUT, string));
}
}

private void captureErr(String string) {
synchronized (this.monitor) {
this.owner.filter2CachedCapturedStrings.remove(Type.filterErr);
this.owner.filter2CachedCapturedStrings.remove(Type.filterAll);
this.capturedStrings.add(new CapturedString(Type.ERR, string));
}
}
Expand All @@ -185,6 +204,7 @@ void append(StringBuilder builder, Predicate<Type> filter) {

void reset() {
synchronized (this.monitor) {
this.owner.filter2CachedCapturedStrings.clear();
this.capturedStrings.clear();
}
}
Expand Down Expand Up @@ -278,7 +298,13 @@ public String toString() {
*/
private enum Type {

OUT, ERR
OUT, ERR;

private static final Predicate<Type> filterOut = OUT::equals;

private static final Predicate<Type> filterErr = ERR::equals;

private static final Predicate<Type> filterAll = (type) -> true;

}

Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down