Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
Comparing source compatibility of opentelemetry-sdk-common-1.41.0-SNAPSHOT.jar against opentelemetry-sdk-common-1.40.0.jar
No changes.
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.common.CompletableResultCode (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.CompletableResultCode failExceptionally(java.lang.Throwable)
+++ NEW METHOD: PUBLIC(+) java.lang.Throwable getFailureThrowable()
+++ NEW ANNOTATION: javax.annotation.Nullable
+++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.common.CompletableResultCode ofExceptionalFailure(java.lang.Throwable)
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Nullable;

/**
Expand All @@ -33,9 +34,19 @@ public static CompletableResultCode ofFailure() {
return FAILURE;
}

/**
* Returns a {@link CompletableResultCode} that has been {@link #failExceptionally(Throwable)
* failed exceptionally}.
*/
public static CompletableResultCode ofExceptionalFailure(Throwable throwable) {
return new CompletableResultCode().failExceptionally(throwable);
}

/**
* Returns a {@link CompletableResultCode} that completes after all the provided {@link
* CompletableResultCode}s complete. If any of the results fail, the result will be failed.
* CompletableResultCode}s complete. If any of the results fail, the result will be failed. If any
* {@link #failExceptionally(Throwable) failed exceptionally}, the result will be failed
* exceptionally with the first {@link Throwable} from {@code codes}.
*/
public static CompletableResultCode ofAll(Collection<CompletableResultCode> codes) {
if (codes.isEmpty()) {
Expand All @@ -44,15 +55,20 @@ public static CompletableResultCode ofAll(Collection<CompletableResultCode> code
CompletableResultCode result = new CompletableResultCode();
AtomicInteger pending = new AtomicInteger(codes.size());
AtomicBoolean failed = new AtomicBoolean();
AtomicReference<Throwable> throwableRef = new AtomicReference<>();
for (CompletableResultCode code : codes) {
code.whenComplete(
() -> {
if (!code.isSuccess()) {
failed.set(true);
Throwable codeThrowable = code.getFailureThrowable();
if (codeThrowable != null) {
throwableRef.compareAndSet(null, codeThrowable);
}
}
if (pending.decrementAndGet() == 0) {
if (failed.get()) {
result.fail();
result.failInternal(throwableRef.get());
} else {
result.succeed();
}
Expand All @@ -71,6 +87,10 @@ public CompletableResultCode() {}
@GuardedBy("lock")
private Boolean succeeded = null;

@Nullable
@GuardedBy("lock")
private Throwable throwable = null;

@GuardedBy("lock")
private final List<Runnable> completionActions = new ArrayList<>();

Expand All @@ -89,11 +109,27 @@ public CompletableResultCode succeed() {
return this;
}

/** Complete this {@link CompletableResultCode} unsuccessfully if it is not already completed. */
/**
* Complete this {@link CompletableResultCode} unsuccessfully if it is not already completed,
* setting the {@link #getFailureThrowable() failure throwable} to {@code null}.
*/
public CompletableResultCode fail() {
return failInternal(null);
}

/**
* Completes this {@link CompletableResultCode} unsuccessfully if it is not already completed,
* setting the {@link #getFailureThrowable() failure throwable} to {@code throwable}.
*/
public CompletableResultCode failExceptionally(Throwable throwable) {
return failInternal(throwable);
}

private CompletableResultCode failInternal(@Nullable Throwable throwable) {
synchronized (lock) {
if (succeeded == null) {
succeeded = false;
this.throwable = throwable;
for (Runnable action : completionActions) {
action.run();
}
Expand All @@ -104,7 +140,7 @@ public CompletableResultCode fail() {

/**
* Obtain the current state of completion. Generally call once completion is achieved via the
* thenRun method.
* {@link #whenComplete(Runnable)} method.
*
* @return the current state of completion
*/
Expand All @@ -114,6 +150,21 @@ public boolean isSuccess() {
}
}

/**
* Returns {@link Throwable} if this {@link CompletableResultCode} was {@link
* #failExceptionally(Throwable) failed exceptionally}. Generally call once completion is achieved
* via the {@link #whenComplete(Runnable)} method.
*
* @return the throwable if failed exceptionally, or null if: {@link #fail() failed without
* exception}, {@link #succeed() succeeded}, or not complete.
*/
@Nullable
public Throwable getFailureThrowable() {
synchronized (lock) {
return throwable;
}
}

/**
* Perform an action on completion. Actions are guaranteed to be called only once.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,32 @@ class CompletableResultCodeTest {

@Test
void ofSuccess() {
assertThat(CompletableResultCode.ofSuccess().isSuccess()).isTrue();
assertThat(CompletableResultCode.ofSuccess())
.satisfies(
code -> {
assertThat(code.isSuccess()).isTrue();
assertThat(code.getFailureThrowable()).isNull();
});
}

@Test
void ofFailure() {
assertThat(CompletableResultCode.ofFailure().isSuccess()).isFalse();
assertThat(CompletableResultCode.ofFailure())
.satisfies(
code -> {
assertThat(code.isSuccess()).isFalse();
assertThat(code.getFailureThrowable()).isNull();
});
}

@Test
void ofExceptionalFailure() {
assertThat(CompletableResultCode.ofExceptionalFailure(new Exception("error")))
.satisfies(
code -> {
assertThat(code.isSuccess()).isFalse();
assertThat(code.getFailureThrowable()).hasMessage("error");
});
}

@Test
Expand Down Expand Up @@ -149,6 +169,24 @@ void ofAllWithFailure() {
.isFalse();
}

@Test
void ofAllWithExceptionalFailure() {
assertThat(
CompletableResultCode.ofAll(
Arrays.asList(
CompletableResultCode.ofSuccess(),
CompletableResultCode.ofFailure(),
CompletableResultCode.ofExceptionalFailure(new Exception("error1")),
CompletableResultCode.ofExceptionalFailure(new Exception("error2")),
CompletableResultCode.ofSuccess())))
.satisfies(
code -> {
assertThat(code.isSuccess()).isFalse();
// failure throwable is set to first throwable seen in the collection
assertThat(code.getFailureThrowable()).hasMessage("error1");
});
}

@Test
void join() {
CompletableResultCode result = new CompletableResultCode();
Expand Down