Skip to content

Commit ec411d9

Browse files
committed
Simplify Promise.onCancel -- no need for wrappers, just return self after setting whenComplete handler.
1 parent ed1b22a commit ec411d9

File tree

8 files changed

+43
-270
lines changed

8 files changed

+43
-270
lines changed

src/main/java/net/tascalate/concurrent/CompletionStageWrapper.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ public static <T> Promise<T> from(CompletionStage<T> stage) {
131131
return from(stage, true);
132132
}
133133

134-
public static <T> Promise<T> from(CompletionStage<T> stage, boolean safePromise) {
134+
public static <T> Promise<T> from(CompletionStage<T> stage, boolean strictPromise) {
135135
Promise<T> result;
136136
if (stage instanceof Future) {
137137
// If we can delegate blocking Future API...
@@ -140,14 +140,14 @@ public static <T> Promise<T> from(CompletionStage<T> stage, boolean safePromise)
140140
// Otherwise fallback to own implementation
141141
result = new CompletionStageWrapper<>(stage);
142142
}
143-
return safePromise ? new SafePromise<>(result) : result;
143+
return strictPromise ? new StrictPromise<>(result) : result;
144144
}
145145

146146
// By default CompletableFuture.cancel() doesn't interrupt a promise from thenCompose(fn)!
147147
// Moreover, exceptionallyAsync and exceptionallyCompose[Async] doesn't play well with cancellation.
148148
// Pessimistically assume this "feature" for all CompletionStage impls. and fix this
149-
static class SafePromise<T> extends AbstractPromiseDecorator<T, Promise<T>> {
150-
SafePromise(Promise<T> delegate) {
149+
static class StrictPromise<T> extends AbstractPromiseDecorator<T, Promise<T>> {
150+
StrictPromise(Promise<T> delegate) {
151151
super(delegate);
152152
}
153153

@@ -165,7 +165,7 @@ public Promise<T> raw() {
165165

166166
@Override
167167
protected <U> Promise<U> wrap(CompletionStage<U> original) {
168-
return new SafePromise<>((Promise<U>)original);
168+
return new StrictPromise<>((Promise<U>)original);
169169
}
170170

171171
@Override

src/main/java/net/tascalate/concurrent/ConfigurableDependentPromise.java

Lines changed: 11 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import static net.tascalate.concurrent.SharedFunctions.cancelPromise;
1919
import static net.tascalate.concurrent.SharedFunctions.iif;
20+
import static net.tascalate.concurrent.SharedFunctions.whenCancel;
2021

2122
import java.time.Duration;
2223
import java.util.Arrays;
@@ -37,8 +38,6 @@
3738
import java.util.function.Supplier;
3839

3940
import net.tascalate.concurrent.core.Decorator;
40-
import net.tascalate.concurrent.decorators.AbstractPromiseDecorator;
41-
4241
/**
4342
*
4443
* <p>{@link DependentPromise} implementation, i.e. concrete wrapper that may keep track origin of this promise
@@ -89,28 +88,6 @@ protected ConfigurableDependentPromise(Promise<T> delegate,
8988
this.cancellableOrigins = cancellableOrigins;
9089
}
9190

92-
private DependentPromise<T> postConstruct() {
93-
if (isEmptyArray(cancellableOrigins)) {
94-
// Nothing to do
95-
}
96-
if (isCancelled()) {
97-
// Wrapped over already cancelled Promise
98-
// So result.cancel() has no effect
99-
// and we have to cancel origins explicitly
100-
// right after construction
101-
cancelPromises(cancellableOrigins, true);
102-
} else if (isDone()) {
103-
// nothing to do
104-
} else {
105-
delegate.whenComplete((r, e) -> {
106-
if (isCancelled()) {
107-
cancelPromises(cancellableOrigins, true);
108-
}
109-
});
110-
}
111-
return this;
112-
}
113-
11491
public static <U> DependentPromise<U> from(Promise<U> source) {
11592
return from(source, PromiseOrigin.NONE);
11693
}
@@ -126,7 +103,8 @@ protected <U> DependentPromise<U> wrap(Promise<U> original, CompletionStage<?>[]
126103
private static <U> DependentPromise<U> doWrap(Promise<U> original,
127104
Set<PromiseOrigin> defaultEnlistOptions,
128105
CompletionStage<?>[] cancellableOrigins) {
129-
if (isEmptyArray(cancellableOrigins)) {
106+
boolean noOrigins = isEmptyArray(cancellableOrigins);
107+
if (noOrigins) {
130108
// Nothing to enlist additionally for this "original" instance
131109
if (original instanceof ConfigurableDependentPromise) {
132110
ConfigurableDependentPromise<U> ioriginal = (ConfigurableDependentPromise<U>)original;
@@ -138,13 +116,9 @@ private static <U> DependentPromise<U> doWrap(Promise<U> original,
138116
}
139117

140118
return new ConfigurableDependentPromise<>(
141-
original, defaultEnlistOptions, cancellableOrigins
142-
).postConstruct();
143-
}
144-
145-
@Override
146-
public DependentPromise<T> onCancel(Runnable code) {
147-
return new ExtraCancellationDependentPromise<>(this, code).postConstruct();
119+
noOrigins ? original : whenCancel(original, () -> cancelPromises(cancellableOrigins, true)),
120+
defaultEnlistOptions, cancellableOrigins
121+
);
148122
}
149123

150124
// All delay overloads delegate to these methods
@@ -750,10 +724,7 @@ public DependentPromise<T> dependent(Set<PromiseOrigin> defaultEnlistOptions) {
750724
if (identicalSets(defaultEnlistOptions, this.defaultEnlistOptions)) {
751725
return this;
752726
} else {
753-
return ConfigurableDependentPromise.from(
754-
null == cancellableOrigins || cancellableOrigins.length == 0 ? delegate : cancellablePromiseOf(delegate),
755-
defaultEnlistOptions
756-
);
727+
return ConfigurableDependentPromise.from(delegate, defaultEnlistOptions);
757728
}
758729
}
759730

@@ -802,31 +773,17 @@ public T join() throws CancellationException, CompletionException {
802773
public boolean isCompletedExceptionally() {
803774
return delegate.isCompletedExceptionally();
804775
}
805-
776+
806777
@Override
807778
public Promise<T> unwrap() {
808-
if (null == cancellableOrigins || cancellableOrigins.length == 0) {
809-
// No state collected, may optimize away own reference
810-
return delegate;
811-
} else {
812-
return cancellablePromiseOf(delegate);
813-
}
779+
return delegate;
814780
}
815-
781+
816782
@Override
817783
public Promise<T> raw() {
818-
if (null == cancellableOrigins || cancellableOrigins.length == 0) {
819-
// No state collected, may optimize away own reference
820-
return delegate.raw();
821-
} else {
822-
return cancellablePromiseOf(delegate.raw());
823-
}
784+
return delegate.raw();
824785
}
825786

826-
protected Promise<T> cancellablePromiseOf(Promise<T> original) {
827-
return new UndecoratedCancellationPromise<>(original, cancellableOrigins);
828-
}
829-
830787
@Override
831788
public CompletableFuture<T> toCompletableFuture() {
832789
return toCompletableFuture(defaultEnlistOrigin());
@@ -930,47 +887,4 @@ private static boolean identicalSets(Set<?> a, Set<?> b) {
930887
private static boolean isEmptyArray(Object[] array) {
931888
return null == array || array.length == 0;
932889
}
933-
934-
static class UndecoratedCancellationPromise<T> extends AbstractPromiseDecorator<T, Promise<T>> {
935-
private final CompletionStage<?>[] dependent;
936-
UndecoratedCancellationPromise(Promise<T> original, CompletionStage<?>[] dependent) {
937-
super(original);
938-
this.dependent = dependent;
939-
}
940-
941-
@Override
942-
public boolean cancel(boolean mayInterruptIfRunning) {
943-
if (super.cancel(mayInterruptIfRunning)) {
944-
cancelPromises(dependent, mayInterruptIfRunning);
945-
return true;
946-
} else {
947-
return false;
948-
}
949-
}
950-
951-
@Override
952-
public Promise<T> unwrap() {
953-
return unwrap(Promise::unwrap);
954-
}
955-
956-
@Override
957-
public Promise<T> raw() {
958-
return unwrap(Promise::raw);
959-
}
960-
961-
private Promise<T> unwrap(Function<Promise<T>, Promise<T>> fn) {
962-
Promise<T> unwrapped = fn.apply(delegate);
963-
if (unwrapped == delegate) {
964-
return this;
965-
} else {
966-
return new UndecoratedCancellationPromise<>(unwrapped, dependent);
967-
}
968-
}
969-
970-
@Override
971-
protected <U> Promise<U> wrap(CompletionStage<U> original) {
972-
// No wrapping by definition
973-
return (Promise<U>)original;
974-
}
975-
}
976890
}

src/main/java/net/tascalate/concurrent/DependentPromise.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,12 @@ public static <U> DependentPromise<U> from(Promise<U> source, Set<PromiseOrigin>
8888
}
8989

9090
@Override
91-
DependentPromise<T> onCancel(Runnable code);
91+
default DependentPromise<T> onCancel(Runnable action) {
92+
// Safe here regardless of origins used
93+
// Max is self-origin, but whenComplete used
94+
// when self is completed already
95+
return SharedFunctions.whenCancel(this, action);
96+
}
9297

9398
@Override
9499
default DependentPromise<T> defaultAsyncOn(Executor executor) {

src/main/java/net/tascalate/concurrent/ExtraCancellationDependentPromise.java

Lines changed: 0 additions & 81 deletions
This file was deleted.

src/main/java/net/tascalate/concurrent/ExtraCancellationPromise.java

Lines changed: 0 additions & 80 deletions
This file was deleted.

0 commit comments

Comments
 (0)