diff --git a/reactor-core/src/main/java/reactor/core/publisher/Mono.java b/reactor-core/src/main/java/reactor/core/publisher/Mono.java index c50395f194..2a6f5e9027 100644 --- a/reactor-core/src/main/java/reactor/core/publisher/Mono.java +++ b/reactor-core/src/main/java/reactor/core/publisher/Mono.java @@ -1,5352 +1,5350 @@ -/* - * Copyright (c) 2016-2022 VMware Inc. or its affiliates, All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package reactor.core.publisher; - -import java.time.Duration; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.Spliterator; -import java.util.concurrent.Callable; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.function.BiConsumer; -import java.util.function.BiFunction; -import java.util.function.BiPredicate; -import java.util.function.BooleanSupplier; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.LongConsumer; -import java.util.function.Predicate; -import java.util.function.Supplier; -import java.util.logging.Level; - -import io.micrometer.core.instrument.MeterRegistry; -import org.reactivestreams.Publisher; -import org.reactivestreams.Subscriber; -import org.reactivestreams.Subscription; - -import reactor.core.CorePublisher; -import reactor.core.CoreSubscriber; -import reactor.core.Disposable; -import reactor.core.Exceptions; -import reactor.core.Fuseable; -import reactor.core.Scannable; -import reactor.core.publisher.FluxOnAssembly.AssemblySnapshot; -import reactor.core.publisher.FluxOnAssembly.CheckpointHeavySnapshot; -import reactor.core.publisher.FluxOnAssembly.CheckpointLightSnapshot; -import reactor.core.scheduler.Scheduler; -import reactor.core.scheduler.Scheduler.Worker; -import reactor.core.scheduler.Schedulers; -import reactor.util.Logger; -import reactor.util.Metrics; -import reactor.util.annotation.Nullable; -import reactor.util.concurrent.Queues; -import reactor.util.context.Context; -import reactor.util.context.ContextView; -import reactor.util.function.Tuple2; -import reactor.util.function.Tuple3; -import reactor.util.function.Tuple4; -import reactor.util.function.Tuple5; -import reactor.util.function.Tuple6; -import reactor.util.function.Tuple7; -import reactor.util.function.Tuple8; -import reactor.util.function.Tuples; -import reactor.core.observability.SignalListener; -import reactor.core.observability.SignalListenerFactory; -import reactor.util.retry.Retry; - -/** - * A Reactive Streams {@link Publisher} with basic rx operators that emits at most one item via the - * {@code onNext} signal then terminates with an {@code onComplete} signal (successful Mono, - * with or without value), or only emits a single {@code onError} signal (failed Mono). - * - *

Most Mono implementations are expected to immediately call {@link Subscriber#onComplete()} - * after having called {@link Subscriber#onNext(T)}. {@link Mono#never() Mono.never()} is an outlier: it doesn't - * emit any signal, which is not technically forbidden although not terribly useful outside - * of tests. On the other hand, a combination of {@code onNext} and {@code onError} is explicitly forbidden. - * - *

- * The recommended way to learn about the {@link Mono} API and discover new operators is - * through the reference documentation, rather than through this javadoc (as opposed to - * learning more about individual operators). See the - * "which operator do I need?" appendix. - * - *

- * - *

- * - *

The rx operators will offer aliases for input {@link Mono} type to preserve the "at most one" - * property of the resulting {@link Mono}. For instance {@link Mono#flatMap flatMap} returns a - * {@link Mono}, while there is a {@link Mono#flatMapMany flatMapMany} alias with possibly more than - * 1 emission. - * - *

{@code Mono} should be used for {@link Publisher} that just completes without any value. - * - *

It is intended to be used in implementations and return types, input parameters should keep - * using raw {@link Publisher} as much as possible. - * - *

Note that using state in the {@code java.util.function} / lambdas used within Mono operators - * should be avoided, as these may be shared between several {@link Subscriber Subscribers}. - * - * @param the type of the single value of this class - * @author Sebastien Deleuze - * @author Stephane Maldini - * @author David Karnok - * @author Simon Baslé - * @see Flux - */ -public abstract class Mono implements CorePublisher { - -// ============================================================================================================== -// Static Generators -// ============================================================================================================== - - /** - * Creates a deferred emitter that can be used with callback-based - * APIs to signal at most one value, a complete or an error signal. - *

- * - *

- * Bridging legacy API involves mostly boilerplate code due to the lack - * of standard types and methods. There are two kinds of API surfaces: - * 1) addListener/removeListener and 2) callback-handler. - *

- * 1) addListener/removeListener pairs
- * To work with such API one has to instantiate the listener, - * call the sink from the listener then register it with the source: - *


-	 * Mono.<String>create(sink -> {
-	 *     HttpListener listener = event -> {
-	 *         if (event.getResponseCode() >= 400) {
-	 *             sink.error(new RuntimeException("Failed"));
-	 *         } else {
-	 *             String body = event.getBody();
-	 *             if (body.isEmpty()) {
-	 *                 sink.success();
-	 *             } else {
-	 *                 sink.success(body.toLowerCase());
-	 *             }
-	 *         }
-	 *     };
-	 *
-	 *     client.addListener(listener);
-	 *
-	 *     sink.onDispose(() -> client.removeListener(listener));
-	 * });
-	 * 
- * Note that this works only with single-value emitting listeners. Otherwise, - * all subsequent signals are dropped. You may have to add {@code client.removeListener(this);} - * to the listener's body. - *

- * 2) callback handler
- * This requires a similar instantiation pattern such as above, but usually the - * successful completion and error are separated into different methods. - * In addition, the legacy API may or may not support some cancellation mechanism. - *


-	 * Mono.<String>create(sink -> {
-	 *     Callback<String> callback = new Callback<String>() {
-	 *         @Override
-	 *         public void onResult(String data) {
-	 *             sink.success(data.toLowerCase());
-	 *         }
-	 *
-	 *         @Override
-	 *         public void onError(Exception e) {
-	 *             sink.error(e);
-	 *         }
-	 *     }
-	 *
-	 *     // without cancellation support:
-	 *
-	 *     client.call("query", callback);
-	 *
-	 *     // with cancellation support:
-	 *
-	 *     AutoCloseable cancel = client.call("query", callback);
-	 *     sink.onDispose(() -> {
-	 *         try {
-	 *             cancel.close();
-	 *         } catch (Exception ex) {
-	 *             Exceptions.onErrorDropped(ex);
-	 *         }
-	 *     });
-	 * });
-	 * 
- * @param callback Consume the {@link MonoSink} provided per-subscriber by Reactor to generate signals. - * @param The type of the value emitted - * @return a {@link Mono} - */ - public static Mono create(Consumer> callback) { - return onAssembly(new MonoCreate<>(callback)); - } - - /** - * Create a {@link Mono} provider that will {@link Supplier#get supply} a target {@link Mono} to subscribe to for - * each {@link Subscriber} downstream. - * - *

- * - *

- * @param supplier a {@link Mono} factory - * @param the element type of the returned Mono instance - * @return a deferred {@link Mono} - * @see #deferContextual(Function) - */ - public static Mono defer(Supplier> supplier) { - return onAssembly(new MonoDefer<>(supplier)); - } - - /** - * Create a {@link Mono} provider that will {@link Function#apply supply} a target {@link Mono} - * to subscribe to for each {@link Subscriber} downstream. - * This operator behaves the same way as {@link #defer(Supplier)}, - * but accepts a {@link Function} that will receive the current {@link ContextView} as an argument. - * - *

- * - *

- * @param contextualMonoFactory a {@link Mono} factory - * @param the element type of the returned Mono instance - * @return a deferred {@link Mono} deriving actual {@link Mono} from context values for each subscription - */ - public static Mono deferContextual(Function> contextualMonoFactory) { - return onAssembly(new MonoDeferContextual<>(contextualMonoFactory)); - } - - /** - * Create a Mono which delays an onNext signal by a given {@link Duration duration} - * on a default Scheduler and completes. - * If the demand cannot be produced in time, an onError will be signalled instead. - * The delay is introduced through the {@link Schedulers#parallel() parallel} default Scheduler. - * - *

- * - *

- * @param duration the duration of the delay - * - * @return a new {@link Mono} - */ - public static Mono delay(Duration duration) { - return delay(duration, Schedulers.parallel()); - } - - /** - * Create a Mono which delays an onNext signal by a given {@link Duration duration} - * on a provided {@link Scheduler} and completes. - * If the demand cannot be produced in time, an onError will be signalled instead. - * - *

- * - *

- * @param duration the {@link Duration} of the delay - * @param timer a time-capable {@link Scheduler} instance to run on - * - * @return a new {@link Mono} - */ - public static Mono delay(Duration duration, Scheduler timer) { - return onAssembly(new MonoDelay(duration.toNanos(), TimeUnit.NANOSECONDS, timer)); - } - - /** - * Create a {@link Mono} that completes without emitting any item. - * - *

- * - *

- * @param the reified {@link Subscriber} type - * - * @return a completed {@link Mono} - */ - public static Mono empty() { - return MonoEmpty.instance(); - } - - /** - * Create a {@link Mono} that terminates with the specified error immediately after - * being subscribed to. - *

- * - *

- * @param error the onError signal - * @param the reified {@link Subscriber} type - * - * @return a failing {@link Mono} - */ - public static Mono error(Throwable error) { - return onAssembly(new MonoError<>(error)); - } - - /** - * Create a {@link Mono} that terminates with an error immediately after being - * subscribed to. The {@link Throwable} is generated by a {@link Supplier}, invoked - * each time there is a subscription and allowing for lazy instantiation. - *

- * - *

- * @param errorSupplier the error signal {@link Supplier} to invoke for each {@link Subscriber} - * @param the reified {@link Subscriber} type - * - * @return a failing {@link Mono} - */ - public static Mono error(Supplier errorSupplier) { - return onAssembly(new MonoErrorSupplied<>(errorSupplier)); - } - - /** - * Pick the first {@link Mono} to emit any signal (value, empty completion or error) - * and replay that signal, effectively behaving like the fastest of these competing - * sources. - *

- * - *

- * @param monos The deferred monos to use. - * @param The type of the function result. - * - * @return a new {@link Mono} behaving like the fastest of its sources. - * @deprecated use {@link #firstWithSignal(Mono[])}. To be removed in reactor 3.5. - */ - @SafeVarargs - @Deprecated - public static Mono first(Mono... monos) { - return firstWithSignal(monos); - } - - /** - * Pick the first {@link Mono} to emit any signal (value, empty completion or error) - * and replay that signal, effectively behaving like the fastest of these competing - * sources. - *

- * - *

- * @param monos The deferred monos to use. - * @param The type of the function result. - * - * @return a new {@link Mono} behaving like the fastest of its sources. - * @deprecated use {@link #firstWithSignal(Iterable)}. To be removed in reactor 3.5. - */ - @Deprecated - public static Mono first(Iterable> monos) { - return firstWithSignal(monos); - } - - /** - * Pick the first {@link Mono} to emit any signal (value, empty completion or error) - * and replay that signal, effectively behaving like the fastest of these competing - * sources. - *

- * - *

- * @param monos The deferred monos to use. - * @param The type of the function result. - * - * @return a new {@link Mono} behaving like the fastest of its sources. - */ - @SafeVarargs - public static Mono firstWithSignal(Mono... monos) { - return onAssembly(new MonoFirstWithSignal<>(monos)); - } - - /** - * Pick the first {@link Mono} to emit any signal (value, empty completion or error) - * and replay that signal, effectively behaving like the fastest of these competing - * sources. - *

- * - *

- * @param monos The deferred monos to use. - * @param The type of the function result. - * - * @return a new {@link Mono} behaving like the fastest of its sources. - */ - public static Mono firstWithSignal(Iterable> monos) { - return onAssembly(new MonoFirstWithSignal<>(monos)); - } - - /** - * Pick the first {@link Mono} source to emit any value and replay that signal, - * effectively behaving like the source that first emits an - * {@link Subscriber#onNext(Object) onNext}. - * - *

- * Valued sources always "win" over an empty source (one that only emits onComplete) - * or a failing source (one that only emits onError). - *

- * When no source can provide a value, this operator fails with a {@link NoSuchElementException} - * (provided there are at least two sources). This exception has a {@link Exceptions#multiple(Throwable...) composite} - * as its {@link Throwable#getCause() cause} that can be used to inspect what went wrong with each source - * (so the composite has as many elements as there are sources). - *

- * Exceptions from failing sources are directly reflected in the composite at the index of the failing source. - * For empty sources, a {@link NoSuchElementException} is added at their respective index. - * One can use {@link Exceptions#unwrapMultiple(Throwable) Exceptions.unwrapMultiple(topLevel.getCause())} - * to easily inspect these errors as a {@link List}. - *

- * Note that like in {@link #firstWithSignal(Iterable)}, an infinite source can be problematic - * if no other source emits onNext. - *

- * - * - * @param monos An {@link Iterable} of the competing source monos - * @param The type of the element in the sources and the resulting mono - * - * @return a new {@link Mono} behaving like the fastest of its sources - */ - public static Mono firstWithValue(Iterable> monos) { - return onAssembly(new MonoFirstWithValue<>(monos)); - } - - /** - * Pick the first {@link Mono} source to emit any value and replay that signal, - * effectively behaving like the source that first emits an - * {@link Subscriber#onNext(Object) onNext}. - *

- * Valued sources always "win" over an empty source (one that only emits onComplete) - * or a failing source (one that only emits onError). - *

- * When no source can provide a value, this operator fails with a {@link NoSuchElementException} - * (provided there are at least two sources). This exception has a {@link Exceptions#multiple(Throwable...) composite} - * as its {@link Throwable#getCause() cause} that can be used to inspect what went wrong with each source - * (so the composite has as many elements as there are sources). - *

- * Exceptions from failing sources are directly reflected in the composite at the index of the failing source. - * For empty sources, a {@link NoSuchElementException} is added at their respective index. - * One can use {@link Exceptions#unwrapMultiple(Throwable) Exceptions.unwrapMultiple(topLevel.getCause())} - * to easily inspect these errors as a {@link List}. - *

- * Note that like in {@link #firstWithSignal(Mono[])}, an infinite source can be problematic - * if no other source emits onNext. - * In case the {@code first} source is already an array-based {@link #firstWithValue(Mono, Mono[])} - * instance, nesting is avoided: a single new array-based instance is created with all the - * sources from {@code first} plus all the {@code others} sources at the same level. - *

- * - * - * @param first the first competing source {@link Mono} - * @param others the other competing sources {@link Mono} - * @param The type of the element in the sources and the resulting mono - * - * @return a new {@link Mono} behaving like the fastest of its sources - */ - @SafeVarargs - public static Mono firstWithValue(Mono first, Mono... others) { - if (first instanceof MonoFirstWithValue) { - @SuppressWarnings("unchecked") - MonoFirstWithValue a = (MonoFirstWithValue) first; - Mono result = a.firstValuedAdditionalSources(others); - if (result != null) { - return result; - } - } - return onAssembly(new MonoFirstWithValue<>(first, others)); - } - - /** - * Expose the specified {@link Publisher} with the {@link Mono} API, and ensure it will emit 0 or 1 item. - * The source emitter will be cancelled on the first `onNext`. - *

- * - *

- * {@link Hooks#onEachOperator(String, Function)} and similar assembly hooks are applied - * unless the source is already a {@link Mono} (including {@link Mono} that was decorated as a {@link Flux}, - * see {@link Flux#from(Publisher)}). - * - * @param source the {@link Publisher} source - * @param the source type - * - * @return the next item emitted as a {@link Mono} - */ - public static Mono from(Publisher source) { - //some sources can be considered already assembled monos - //all conversion methods (from, fromDirect, wrap) must accommodate for this - if (source instanceof Mono) { - @SuppressWarnings("unchecked") - Mono casted = (Mono) source; - return casted; - } - if (source instanceof FluxSourceMono - || source instanceof FluxSourceMonoFuseable) { - @SuppressWarnings("unchecked") - FluxFromMonoOperator wrapper = (FluxFromMonoOperator) source; - @SuppressWarnings("unchecked") - Mono extracted = (Mono) wrapper.source; - return extracted; - } - - //we delegate to `wrap` and apply assembly hooks - @SuppressWarnings("unchecked") Publisher downcasted = (Publisher) source; - return onAssembly(wrap(downcasted, true)); - } - - /** - * Create a {@link Mono} producing its value using the provided {@link Callable}. If - * the Callable resolves to {@code null}, the resulting Mono completes empty. - * - *

- * - *

- * @param supplier {@link Callable} that will produce the value - * @param type of the expected value - * - * @return A {@link Mono}. - */ - public static Mono fromCallable(Callable supplier) { - return onAssembly(new MonoCallable<>(supplier)); - } - - /** - * Create a {@link Mono}, producing its value using the provided {@link CompletionStage}. - * - *

- * - *

- * If the completionStage is also a {@link Future}, cancelling the Mono will cancel the future. - * Use {@link #fromFuture(CompletableFuture, boolean)} with {@code suppressCancellation} set to - * {@code true} if you need to suppress cancellation propagation. - * - * @param completionStage {@link CompletionStage} that will produce a value (or a null to - * complete immediately) - * @param type of the expected value - * @return A {@link Mono}. - */ - public static Mono fromCompletionStage(CompletionStage completionStage) { - return onAssembly(new MonoCompletionStage<>(completionStage, false)); - } - - /** - * Create a {@link Mono} that wraps a lazily-supplied {@link CompletionStage} on subscription, - * emitting the value produced by the {@link CompletionStage}. - * - *

- * - *

- * If the completionStage is also a {@link Future}, cancelling the Mono will cancel the future. - * Use {@link #fromFuture(CompletableFuture, boolean)} with {@code suppressCancellation} set to - * {@code true} if you need to suppress cancellation propagation. - * - * @param stageSupplier The {@link Supplier} of a {@link CompletionStage} that will produce a value (or a null to - * complete immediately). This allows lazy triggering of CompletionStage-based APIs. - * @param type of the expected value - * @return A {@link Mono}. - */ - public static Mono fromCompletionStage(Supplier> stageSupplier) { - return defer(() -> onAssembly(new MonoCompletionStage<>(stageSupplier.get(), false))); - } - - /** - * Convert a {@link Publisher} to a {@link Mono} without any cardinality check - * (ie this method doesn't cancel the source past the first element). - * Conversion transparently returns {@link Mono} sources without wrapping and otherwise - * supports {@link Fuseable} sources. - * Note this is an advanced interoperability operator that implies you know the - * {@link Publisher} you are converting follows the {@link Mono} semantics and only - * ever emits one element. - *

- * {@link Hooks#onEachOperator(String, Function)} and similar assembly hooks are applied - * unless the source is already a {@link Mono}. - * - * @param source the Mono-compatible {@link Publisher} to wrap - * @param type of the value emitted by the publisher - * @return a wrapped {@link Mono} - */ - public static Mono fromDirect(Publisher source){ - //some sources can be considered already assembled monos - //all conversion methods (from, fromDirect, wrap) must accommodate for this - if(source instanceof Mono){ - @SuppressWarnings("unchecked") - Mono m = (Mono)source; - return m; - } - if (source instanceof FluxSourceMono - || source instanceof FluxSourceMonoFuseable) { - @SuppressWarnings("unchecked") - FluxFromMonoOperator wrapper = (FluxFromMonoOperator) source; - @SuppressWarnings("unchecked") - Mono extracted = (Mono) wrapper.source; - return extracted; - } - - //we delegate to `wrap` and apply assembly hooks - @SuppressWarnings("unchecked") Publisher downcasted = (Publisher) source; - return onAssembly(wrap(downcasted, false)); - } - - /** - * Create a {@link Mono}, producing its value using the provided {@link CompletableFuture} - * and cancelling the future if the Mono gets cancelled. - * - *

- * - *

- * Use {@link #fromFuture(CompletableFuture, boolean)} with {@code suppressCancellation} set to - * {@code true} if you need to suppress cancellation propagation. - * - * @param future {@link CompletableFuture} that will produce a value (or a null to - * complete immediately) - * @param type of the expected value - * @return A {@link Mono}. - * @see #fromCompletionStage(CompletionStage) fromCompletionStage for a generalization - */ - public static Mono fromFuture(CompletableFuture future) { - return fromFuture(future, false); - } - - /** - * Create a {@link Mono}, producing its value using the provided {@link CompletableFuture} - * and optionally cancelling the future if the Mono gets cancelled (if {@code suppressCancel == false}). - * - *

- * - *

- * - * @param future {@link CompletableFuture} that will produce a value (or a null to complete immediately) - * @param suppressCancel {@code true} to prevent cancellation of the future when the Mono is cancelled, - * {@code false} otherwise (the default) - * @param type of the expected value - * @return A {@link Mono}. - */ - public static Mono fromFuture(CompletableFuture future, boolean suppressCancel) { - return onAssembly(new MonoCompletionStage<>(future, suppressCancel)); - } - - /** - * Create a {@link Mono} that wraps a lazily-supplied {@link CompletableFuture} on subscription, - * emitting the value produced by the future and cancelling the future if the Mono gets cancelled. - * - *

- * - *

- * - * @param futureSupplier The {@link Supplier} of a {@link CompletableFuture} that will produce a value - * (or a null to complete immediately). This allows lazy triggering of future-based APIs. - * @param type of the expected value - * @return A {@link Mono}. - * @see #fromCompletionStage(Supplier) fromCompletionStage for a generalization - */ - public static Mono fromFuture(Supplier> futureSupplier) { - return fromFuture(futureSupplier, false); - } - - /** - * Create a {@link Mono} that wraps a lazily-supplied {@link CompletableFuture} on subscription, - * emitting the value produced by the future and optionally cancelling the future if the Mono gets cancelled - * (if {@code suppressCancel == false}). - * - *

- * - *

- * - * @param futureSupplier The {@link Supplier} of a {@link CompletableFuture} that will produce a value - * (or a null to complete immediately). This allows lazy triggering of future-based APIs. - * @param suppressCancel {@code true} to prevent cancellation of the future when the Mono is cancelled, - * {@code false} otherwise (the default) - * @param type of the expected value - * @return A {@link Mono}. - * @see #fromCompletionStage(Supplier) fromCompletionStage for a generalization - */ - public static Mono fromFuture(Supplier> futureSupplier, boolean suppressCancel) { - return defer(() -> onAssembly(new MonoCompletionStage<>(futureSupplier.get(), suppressCancel))); - } - - /** - * Create a {@link Mono} that completes empty once the provided {@link Runnable} has - * been executed. - * - *

- * - *

- * @param runnable {@link Runnable} that will be executed before emitting the completion signal - * - * @param The generic type of the upstream, which is preserved by this operator - * @return A {@link Mono}. - */ - public static Mono fromRunnable(Runnable runnable) { - return onAssembly(new MonoRunnable<>(runnable)); - } - - /** - * Create a {@link Mono}, producing its value using the provided {@link Supplier}. If - * the Supplier resolves to {@code null}, the resulting Mono completes empty. - * - *

- * - *

- * @param supplier {@link Supplier} that will produce the value - * @param type of the expected value - * - * @return A {@link Mono}. - */ - public static Mono fromSupplier(Supplier supplier) { - return onAssembly(new MonoSupplier<>(supplier)); - } - - - /** - * Create a new {@link Mono} that ignores elements from the source (dropping them), - * but completes when the source completes. - * - *

- * - *

- * - *

Discard Support: This operator discards the element from the source. - * - * @param source the {@link Publisher} to ignore - * @param the source type of the ignored data - * - * @return a new completable {@link Mono}. - */ - public static Mono ignoreElements(Publisher source) { - return onAssembly(new MonoIgnorePublisher<>(source)); - } - - /** - * Create a new {@link Mono} that emits the specified item, which is captured at - * instantiation time. - * - *

- * - *

- * @param data the only item to onNext - * @param the type of the produced item - * - * @return a {@link Mono}. - */ - public static Mono just(T data) { - return onAssembly(new MonoJust<>(data)); - } - - /** - * Create a new {@link Mono} that emits the specified item if {@link Optional#isPresent()} otherwise only emits - * onComplete. - * - *

- * - *

- * @param data the {@link Optional} item to onNext or onComplete if not present - * @param the type of the produced item - * - * @return a {@link Mono}. - */ - public static Mono justOrEmpty(@Nullable Optional data) { - return data != null && data.isPresent() ? just(data.get()) : empty(); - } - - /** - * Create a new {@link Mono} that emits the specified item if non null otherwise only emits - * onComplete. - * - *

- * - *

- * @param data the item to onNext or onComplete if null - * @param the type of the produced item - * - * @return a {@link Mono}. - */ - public static Mono justOrEmpty(@Nullable T data) { - return data != null ? just(data) : empty(); - } - - - /** - * Return a {@link Mono} that will never signal any data, error or completion signal, - * essentially running indefinitely. - *

- * - *

- * @param the {@link Subscriber} type target - * - * @return a never completing {@link Mono} - */ - public static Mono never() { - return MonoNever.instance(); - } - - /** - * Returns a Mono that emits a Boolean value that indicates whether two Publisher sequences are the - * same by comparing the items emitted by each Publisher pairwise. - *

- * - * - * @param source1 the first Publisher to compare - * @param source2 the second Publisher to compare - * @param the type of items emitted by each Publisher - * @return a Mono that emits a Boolean value that indicates whether the two sequences are the same - */ - public static Mono sequenceEqual(Publisher source1, Publisher source2) { - return sequenceEqual(source1, source2, equalsBiPredicate(), Queues.SMALL_BUFFER_SIZE); - } - - /** - * Returns a Mono that emits a Boolean value that indicates whether two Publisher sequences are the - * same by comparing the items emitted by each Publisher pairwise based on the results of a specified - * equality function. - *

- * - * - * @param source1 the first Publisher to compare - * @param source2 the second Publisher to compare - * @param isEqual a function used to compare items emitted by each Publisher - * @param the type of items emitted by each Publisher - * @return a Mono that emits a Boolean value that indicates whether the two Publisher two sequences - * are the same according to the specified function - */ - public static Mono sequenceEqual(Publisher source1, Publisher source2, - BiPredicate isEqual) { - return sequenceEqual(source1, source2, isEqual, Queues.SMALL_BUFFER_SIZE); - } - - /** - * Returns a Mono that emits a Boolean value that indicates whether two Publisher sequences are the - * same by comparing the items emitted by each Publisher pairwise based on the results of a specified - * equality function. - *

- * - * - * @param source1 the first Publisher to compare - * @param source2 the second Publisher to compare - * @param isEqual a function used to compare items emitted by each Publisher - * @param prefetch the number of items to prefetch from the first and second source Publisher - * @param the type of items emitted by each Publisher - * @return a Mono that emits a Boolean value that indicates whether the two Publisher two sequences - * are the same according to the specified function - */ - public static Mono sequenceEqual(Publisher source1, - Publisher source2, - BiPredicate isEqual, int prefetch) { - return onAssembly(new MonoSequenceEqual<>(source1, source2, isEqual, prefetch)); - } - - /** - * Uses a resource, generated by a supplier for each individual Subscriber, while streaming the value from a - * Mono derived from the same resource and makes sure the resource is released if the - * sequence terminates or the Subscriber cancels. - *

- *

    - *
  • For eager cleanup, unlike in {@link Flux#using(Callable, Function, Consumer, boolean) Flux}, - * in the case of a valued {@link Mono} the cleanup happens just before passing the value to downstream. - * In all cases, exceptions raised by the eager cleanup {@link Consumer} may override the terminal event, - * discarding the element if the derived {@link Mono} was valued.
  • - *
  • Non-eager cleanup will drop any exception.
  • - *
- *

- * - * - * @param resourceSupplier a {@link Callable} that is called on subscribe to create the resource - * @param sourceSupplier a {@link Mono} factory to create the Mono depending on the created resource - * @param resourceCleanup invoked on completion to clean-up the resource - * @param eager set to true to clean before any signal (including onNext) is passed downstream - * @param emitted type - * @param resource type - * - * @return new {@link Mono} - */ - public static Mono using(Callable resourceSupplier, - Function> sourceSupplier, - Consumer resourceCleanup, - boolean eager) { - return onAssembly(new MonoUsing<>(resourceSupplier, sourceSupplier, - resourceCleanup, eager)); - } - - /** - * Uses a resource, generated by a supplier for each individual Subscriber, while streaming the value from a - * Mono derived from the same resource and makes sure the resource is released if the - * sequence terminates or the Subscriber cancels. - *

- * Unlike in {@link Flux#using(Callable, Function, Consumer) Flux}, in the case of a valued {@link Mono} the cleanup - * happens just before passing the value to downstream. In all cases, exceptions raised by the cleanup - * {@link Consumer} may override the terminal event, discarding the element if the derived {@link Mono} was valued. - *

- * - * - * @param resourceSupplier a {@link Callable} that is called on subscribe to create the resource - * @param sourceSupplier a {@link Mono} factory to create the Mono depending on the created resource - * @param resourceCleanup invoked on completion to clean-up the resource - * @param emitted type - * @param resource type - * - * @return new {@link Mono} - */ - public static Mono using(Callable resourceSupplier, - Function> sourceSupplier, - Consumer resourceCleanup) { - return using(resourceSupplier, sourceSupplier, resourceCleanup, true); - } - - - /** - * Uses a resource, generated by a {@link Publisher} for each individual {@link Subscriber}, - * to derive a {@link Mono}. Note that all steps of the operator chain that would need the - * resource to be in an open stable state need to be described inside the {@code resourceClosure} - * {@link Function}. - *

- * Unlike in {@link Flux#usingWhen(Publisher, Function, Function) the Flux counterpart}, ALL signals are deferred - * until the {@link Mono} terminates and the relevant {@link Function} generates and invokes a "cleanup" - * {@link Publisher}. This is because a failure in the cleanup Publisher - * must result in a lone {@code onError} signal in the downstream {@link Mono} (any potential value in the - * derived {@link Mono} is discarded). Here are the various scenarios that can play out: - *

    - *
  • empty Mono, asyncCleanup ends with {@code onComplete()}: downstream receives {@code onComplete()}
  • - *
  • empty Mono, asyncCleanup ends with {@code onError(t)}: downstream receives {@code onError(t)}
  • - *
  • valued Mono, asyncCleanup ends with {@code onComplete()}: downstream receives {@code onNext(value),onComplete()}
  • - *
  • valued Mono, asyncCleanup ends with {@code onError(t)}: downstream receives {@code onError(t)}, {@code value} is discarded
  • - *
  • error(e) Mono, asyncCleanup ends with {@code onComplete()}: downstream receives {@code onError(e)}
  • - *
  • error(e) Mono, asyncCleanup ends with {@code onError(t)}: downstream receives {@code onError(t)}, t suppressing e
  • - *
- *

- * - *

- * Note that if the resource supplying {@link Publisher} emits more than one resource, the - * subsequent resources are dropped ({@link Operators#onNextDropped(Object, Context)}). If - * the publisher errors AFTER having emitted one resource, the error is also silently dropped - * ({@link Operators#onErrorDropped(Throwable, Context)}). - * An empty completion or error without at least one onNext signal (no resource supplied) - * triggers a short-circuit of the main sequence with the same terminal signal - * (no cleanup is invoked). - * - *

Discard Support: This operator discards any source element if the {@code asyncCleanup} handler fails. - * - * @param resourceSupplier a {@link Publisher} that "generates" the resource, - * subscribed for each subscription to the main sequence - * @param resourceClosure a factory to derive a {@link Mono} from the supplied resource - * @param asyncCleanup an asynchronous resource cleanup invoked when the resource - * closure terminates (with onComplete, onError or cancel) - * @param the type of elements emitted by the resource closure, and thus the main sequence - * @param the type of the resource object - * - * @return a new {@link Mono} built around a "transactional" resource, with deferred emission until the - * asynchronous cleanup sequence completes - */ - public static Mono usingWhen(Publisher resourceSupplier, - Function> resourceClosure, - Function> asyncCleanup) { - return usingWhen(resourceSupplier, resourceClosure, asyncCleanup, - (res, error) -> asyncCleanup.apply(res), - asyncCleanup); - } - - /** - * Uses a resource, generated by a {@link Publisher} for each individual {@link Subscriber}, - * to derive a {@link Mono}.Note that all steps of the operator chain that would need the - * resource to be in an open stable state need to be described inside the {@code resourceClosure} - * {@link Function}. - *

- * Unlike in {@link Flux#usingWhen(Publisher, Function, Function, BiFunction, Function) the Flux counterpart}, - * ALL signals are deferred until the {@link Mono} terminates and the relevant {@link Function} - * generates and invokes a "cleanup" {@link Publisher}. This is because a failure in the cleanup Publisher - * must result in a lone {@code onError} signal in the downstream {@link Mono} (any potential value in the - * derived {@link Mono} is discarded). Here are the various scenarios that can play out: - *

    - *
  • empty Mono, asyncComplete ends with {@code onComplete()}: downstream receives {@code onComplete()}
  • - *
  • empty Mono, asyncComplete ends with {@code onError(t)}: downstream receives {@code onError(t)}
  • - *
  • valued Mono, asyncComplete ends with {@code onComplete()}: downstream receives {@code onNext(value),onComplete()}
  • - *
  • valued Mono, asyncComplete ends with {@code onError(t)}: downstream receives {@code onError(t)}, {@code value} is discarded
  • - *
  • error(e) Mono, errorComplete ends with {@code onComplete()}: downstream receives {@code onError(e)}
  • - *
  • error(e) Mono, errorComplete ends with {@code onError(t)}: downstream receives {@code onError(t)}, t suppressing e
  • - *
- *

- * - *

- * Individual cleanups can also be associated with mono cancellation and - * error terminations: - *

- * - *

- * Note that if the resource supplying {@link Publisher} emits more than one resource, the - * subsequent resources are dropped ({@link Operators#onNextDropped(Object, Context)}). If - * the publisher errors AFTER having emitted one resource, the error is also silently dropped - * ({@link Operators#onErrorDropped(Throwable, Context)}). - * An empty completion or error without at least one onNext signal (no resource supplied) - * triggers a short-circuit of the main sequence with the same terminal signal - * (no cleanup is invoked). - * - *

Discard Support: This operator discards the element if the {@code asyncComplete} handler fails. - * - * @param resourceSupplier a {@link Publisher} that "generates" the resource, - * subscribed for each subscription to the main sequence - * @param resourceClosure a factory to derive a {@link Mono} from the supplied resource - * @param asyncComplete an asynchronous resource cleanup invoked if the resource closure terminates with onComplete - * @param asyncError an asynchronous resource cleanup invoked if the resource closure terminates with onError. - * The terminating error is provided to the {@link BiFunction} - * @param asyncCancel an asynchronous resource cleanup invoked if the resource closure is cancelled. - * When {@code null}, the {@code asyncComplete} path is used instead. - * @param the type of elements emitted by the resource closure, and thus the main sequence - * @param the type of the resource object - * - * @return a new {@link Mono} built around a "transactional" resource, with several - * termination path triggering asynchronous cleanup sequences - * - */ - public static Mono usingWhen(Publisher resourceSupplier, - Function> resourceClosure, - Function> asyncComplete, - BiFunction> asyncError, - //the operator itself accepts null for asyncCancel, but we won't in the public API - Function> asyncCancel) { - return onAssembly(new MonoUsingWhen<>(resourceSupplier, resourceClosure, - asyncComplete, asyncError, asyncCancel)); - } - - /** - * Aggregate given publishers into a new {@literal Mono} that will be fulfilled - * when all of the given {@literal sources} have completed. An error will cause - * pending results to be cancelled and immediate error emission to the returned {@link Mono}. - *

- * - *

- * @param sources The sources to use. - * - * @return a {@link Mono}. - */ - public static Mono when(Publisher... sources) { - if (sources.length == 0) { - return empty(); - } - if (sources.length == 1) { - return empty(sources[0]); - } - return onAssembly(new MonoWhen(false, sources)); - } - - - /** - * Aggregate given publishers into a new {@literal Mono} that will be - * fulfilled when all of the given {@literal Publishers} have completed. - * An error will cause pending results to be cancelled and immediate error emission - * to the returned {@link Mono}. - * - *

- * - *

- * - * @param sources The sources to use. - * - * @return a {@link Mono}. - */ - public static Mono when(final Iterable> sources) { - return onAssembly(new MonoWhen(false, sources)); - } - - /** - * Aggregate given publishers into a new {@literal Mono} that will be - * fulfilled when all of the given {@literal sources} have completed. Errors from - * the sources are delayed. - * If several Publishers error, the exceptions are combined (as suppressed exceptions on a root exception). - * - *

- * - *

- * - * @param sources The sources to use. - * - * @return a {@link Mono}. - */ - public static Mono whenDelayError(final Iterable> sources) { - return onAssembly(new MonoWhen(true, sources)); - } - - /** - * Merge given publishers into a new {@literal Mono} that will be fulfilled when - * all of the given {@literal sources} have completed. Errors from the sources are delayed. - * If several Publishers error, the exceptions are combined (as suppressed exceptions on a root exception). - * - *

- * - *

- * @param sources The sources to use. - * - * @return a {@link Mono}. - */ - public static Mono whenDelayError(Publisher... sources) { - if (sources.length == 0) { - return empty(); - } - if (sources.length == 1) { - return empty(sources[0]); - } - return onAssembly(new MonoWhen(true, sources)); - } - - /** - * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} - * have produced an item, aggregating their values into a {@link Tuple2}. - * An error or empty completion of any source will cause other sources - * to be cancelled and the resulting Mono to immediately error or complete, respectively. - * - *

- * - *

- * @param p1 The first upstream {@link Publisher} to subscribe to. - * @param p2 The second upstream {@link Publisher} to subscribe to. - * @param type of the value from p1 - * @param type of the value from p2 - * - * @return a {@link Mono}. - */ - public static Mono> zip(Mono p1, Mono p2) { - return zip(p1, p2, Flux.tuple2Function()); - } - - /** - * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} - * have produced an item, aggregating their values as defined by the combinator function. - * An error or empty completion of any source will cause other sources - * to be cancelled and the resulting Mono to immediately error or complete, respectively. - * - *

- * - *

- * @param p1 The first upstream {@link Publisher} to subscribe to. - * @param p2 The second upstream {@link Publisher} to subscribe to. - * @param combinator a {@link BiFunction} combinator function when both sources - * complete - * @param type of the value from p1 - * @param type of the value from p2 - * @param output value - * - * @return a {@link Mono}. - */ - public static Mono zip(Mono p1, Mono p2, BiFunction combinator) { - return onAssembly(new MonoZip(false, p1, p2, combinator)); - } - - /** - * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} - * have produced an item, aggregating their values into a {@link Tuple3}. - * An error or empty completion of any source will cause other sources - * to be cancelled and the resulting Mono to immediately error or complete, respectively. - * - *

- * - *

- * @param p1 The first upstream {@link Publisher} to subscribe to. - * @param p2 The second upstream {@link Publisher} to subscribe to. - * @param p3 The third upstream {@link Publisher} to subscribe to. - * @param type of the value from p1 - * @param type of the value from p2 - * @param type of the value from p3 - * - * @return a {@link Mono}. - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static Mono> zip(Mono p1, Mono p2, Mono p3) { - return onAssembly(new MonoZip(false, a -> Tuples.fromArray((Object[])a), p1, p2, p3)); - } - - /** - * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} - * have produced an item, aggregating their values into a {@link Tuple4}. - * An error or empty completion of any source will cause other sources - * to be cancelled and the resulting Mono to immediately error or complete, respectively. - * - *

- * - *

- * @param p1 The first upstream {@link Publisher} to subscribe to. - * @param p2 The second upstream {@link Publisher} to subscribe to. - * @param p3 The third upstream {@link Publisher} to subscribe to. - * @param p4 The fourth upstream {@link Publisher} to subscribe to. - * @param type of the value from p1 - * @param type of the value from p2 - * @param type of the value from p3 - * @param type of the value from p4 - * - * @return a {@link Mono}. - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static Mono> zip(Mono p1, - Mono p2, - Mono p3, - Mono p4) { - return onAssembly(new MonoZip(false, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4)); - } - - /** - * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} - * have produced an item, aggregating their values into a {@link Tuple5}. - * An error or empty completion of any source will cause other sources - * to be cancelled and the resulting Mono to immediately error or complete, respectively. - * - *

- * - *

- * @param p1 The first upstream {@link Publisher} to subscribe to. - * @param p2 The second upstream {@link Publisher} to subscribe to. - * @param p3 The third upstream {@link Publisher} to subscribe to. - * @param p4 The fourth upstream {@link Publisher} to subscribe to. - * @param p5 The fifth upstream {@link Publisher} to subscribe to. - * @param type of the value from p1 - * @param type of the value from p2 - * @param type of the value from p3 - * @param type of the value from p4 - * @param type of the value from p5 - * - * @return a {@link Mono}. - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static Mono> zip(Mono p1, - Mono p2, - Mono p3, - Mono p4, - Mono p5) { - return onAssembly(new MonoZip(false, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5)); - } - - /** - * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} - * have produced an item, aggregating their values into a {@link Tuple6}. - * An error or empty completion of any source will cause other sources - * to be cancelled and the resulting Mono to immediately error or complete, respectively. - * - *

- * - *

- * @param p1 The first upstream {@link Publisher} to subscribe to. - * @param p2 The second upstream {@link Publisher} to subscribe to. - * @param p3 The third upstream {@link Publisher} to subscribe to. - * @param p4 The fourth upstream {@link Publisher} to subscribe to. - * @param p5 The fifth upstream {@link Publisher} to subscribe to. - * @param p6 The sixth upstream {@link Publisher} to subscribe to. - * @param type of the value from p1 - * @param type of the value from p2 - * @param type of the value from p3 - * @param type of the value from p4 - * @param type of the value from p5 - * @param type of the value from p6 - * - * @return a {@link Mono}. - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static Mono> zip(Mono p1, - Mono p2, - Mono p3, - Mono p4, - Mono p5, - Mono p6) { - return onAssembly(new MonoZip(false, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5, p6)); - } - - /** - * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} - * have produced an item, aggregating their values into a {@link Tuple7}. - * An error or empty completion of any source will cause other sources - * to be cancelled and the resulting Mono to immediately error or complete, respectively. - * - *

- * - *

- * @param p1 The first upstream {@link Publisher} to subscribe to. - * @param p2 The second upstream {@link Publisher} to subscribe to. - * @param p3 The third upstream {@link Publisher} to subscribe to. - * @param p4 The fourth upstream {@link Publisher} to subscribe to. - * @param p5 The fifth upstream {@link Publisher} to subscribe to. - * @param p6 The sixth upstream {@link Publisher} to subscribe to. - * @param p7 The seventh upstream {@link Publisher} to subscribe to. - * @param type of the value from p1 - * @param type of the value from p2 - * @param type of the value from p3 - * @param type of the value from p4 - * @param type of the value from p5 - * @param type of the value from p6 - * @param type of the value from p7 - * - * @return a {@link Mono}. - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static Mono> zip(Mono p1, - Mono p2, - Mono p3, - Mono p4, - Mono p5, - Mono p6, - Mono p7) { - return onAssembly(new MonoZip(false, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5, p6, p7)); - } - - /** - * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} - * have produced an item, aggregating their values into a {@link Tuple8}. - * An error or empty completion of any source will cause other sources - * to be cancelled and the resulting Mono to immediately error or complete, respectively. - * - *

- * - *

- * @param p1 The first upstream {@link Publisher} to subscribe to. - * @param p2 The second upstream {@link Publisher} to subscribe to. - * @param p3 The third upstream {@link Publisher} to subscribe to. - * @param p4 The fourth upstream {@link Publisher} to subscribe to. - * @param p5 The fifth upstream {@link Publisher} to subscribe to. - * @param p6 The sixth upstream {@link Publisher} to subscribe to. - * @param p7 The seventh upstream {@link Publisher} to subscribe to. - * @param p8 The eight upstream {@link Publisher} to subscribe to. - * @param type of the value from p1 - * @param type of the value from p2 - * @param type of the value from p3 - * @param type of the value from p4 - * @param type of the value from p5 - * @param type of the value from p6 - * @param type of the value from p7 - * @param type of the value from p8 - * - * @return a {@link Mono}. - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static Mono> zip(Mono p1, - Mono p2, - Mono p3, - Mono p4, - Mono p5, - Mono p6, - Mono p7, - Mono p8) { - return onAssembly(new MonoZip(false, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5, p6, p7, p8)); - } - - /** - * Aggregate given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal - * Monos} have produced an item, aggregating their values according to the provided combinator function. - * An error or empty completion of any source will cause other sources - * to be cancelled and the resulting Mono to immediately error or complete, respectively. - * - *

- * - *

- * - * @param monos The monos to use. - * @param combinator the function to transform the combined array into an arbitrary - * object. - * @param the combined result - * - * @return a {@link Mono}. - */ - public static Mono zip(final Iterable> monos, Function combinator) { - return onAssembly(new MonoZip<>(false, combinator, monos)); - } - - /** - * Aggregate given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal - * Monos} have produced an item, aggregating their values according to the provided combinator function. - * An error or empty completion of any source will cause other sources - * to be cancelled and the resulting Mono to immediately error or complete, respectively. - *

- * - *

- * @param monos The monos to use. - * @param combinator the function to transform the combined array into an arbitrary - * object. - * @param the combined result - * - * @return a {@link Mono}. - */ - public static Mono zip(Function combinator, Mono... monos) { - if (monos.length == 0) { - return empty(); - } - if (monos.length == 1) { - return monos[0].map(d -> combinator.apply(new Object[]{d})); - } - return onAssembly(new MonoZip<>(false, combinator, monos)); - } - - /** - * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} - * have produced an item, aggregating their values into a {@link Tuple2} and delaying errors. - * If a Mono source completes without value, the other source is run to completion then the - * resulting {@link Mono} completes empty. - * If both Monos error, the two exceptions are combined (as suppressed exceptions on a root exception). - * - *

- * - *

- * @param p1 The first upstream {@link Publisher} to subscribe to. - * @param p2 The second upstream {@link Publisher} to subscribe to. - * @param type of the value from p1 - * @param type of the value from p2 - * - * @return a {@link Mono}. - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static Mono> zipDelayError(Mono p1, Mono p2) { - return onAssembly(new MonoZip(true, a -> Tuples.fromArray((Object[])a), p1, p2)); - } - - /** - * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Mono Monos} - * have produced an item, aggregating their values into a {@link Tuple3} and delaying errors. - * If a Mono source completes without value, all other sources are run to completion then - * the resulting {@link Mono} completes empty. - * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). - * - *

- * - *

- * @param p1 The first upstream {@link Publisher} to subscribe to. - * @param p2 The second upstream {@link Publisher} to subscribe to. - * @param p3 The third upstream {@link Publisher} to subscribe to. - * @param type of the value from p1 - * @param type of the value from p2 - * @param type of the value from p3 - * - * @return a {@link Mono}. - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static Mono> zipDelayError(Mono p1, Mono p2, Mono p3) { - return onAssembly(new MonoZip(true, a -> Tuples.fromArray((Object[])a), p1, p2, p3)); - } - - /** - * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} - * have produced an item, aggregating their values into a {@link Tuple4} and delaying errors. - * If a Mono source completes without value, all other sources are run to completion then - * the resulting {@link Mono} completes empty. - * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). - * - *

- * - *

- * @param p1 The first upstream {@link Publisher} to subscribe to. - * @param p2 The second upstream {@link Publisher} to subscribe to. - * @param p3 The third upstream {@link Publisher} to subscribe to. - * @param p4 The fourth upstream {@link Publisher} to subscribe to. - * @param type of the value from p1 - * @param type of the value from p2 - * @param type of the value from p3 - * @param type of the value from p4 - * - * @return a {@link Mono}. - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static Mono> zipDelayError(Mono p1, - Mono p2, - Mono p3, - Mono p4) { - return onAssembly(new MonoZip(true, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4)); - } - - /** - * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} - * have produced an item, aggregating their values into a {@link Tuple5} and delaying errors. - * If a Mono source completes without value, all other sources are run to completion then - * the resulting {@link Mono} completes empty. - * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). - *

- * - *

- * @param p1 The first upstream {@link Publisher} to subscribe to. - * @param p2 The second upstream {@link Publisher} to subscribe to. - * @param p3 The third upstream {@link Publisher} to subscribe to. - * @param p4 The fourth upstream {@link Publisher} to subscribe to. - * @param p5 The fifth upstream {@link Publisher} to subscribe to. - * @param type of the value from p1 - * @param type of the value from p2 - * @param type of the value from p3 - * @param type of the value from p4 - * @param type of the value from p5 - * - * @return a {@link Mono}. - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static Mono> zipDelayError(Mono p1, - Mono p2, - Mono p3, - Mono p4, - Mono p5) { - return onAssembly(new MonoZip(true, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5)); - } - - /** - * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} - * have produced an item, aggregating their values into a {@link Tuple6} and delaying errors. - * If a Mono source completes without value, all other sources are run to completion then - * the resulting {@link Mono} completes empty. - * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). - * - *

- * - *

- * @param p1 The first upstream {@link Publisher} to subscribe to. - * @param p2 The second upstream {@link Publisher} to subscribe to. - * @param p3 The third upstream {@link Publisher} to subscribe to. - * @param p4 The fourth upstream {@link Publisher} to subscribe to. - * @param p5 The fifth upstream {@link Publisher} to subscribe to. - * @param p6 The sixth upstream {@link Publisher} to subscribe to. - * @param type of the value from p1 - * @param type of the value from p2 - * @param type of the value from p3 - * @param type of the value from p4 - * @param type of the value from p5 - * @param type of the value from p6 - * - * @return a {@link Mono}. - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static Mono> zipDelayError(Mono p1, - Mono p2, - Mono p3, - Mono p4, - Mono p5, - Mono p6) { - return onAssembly(new MonoZip(true, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5, p6)); - } - - /** - * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} - * have produced an item, aggregating their values into a {@link Tuple7} and delaying errors. - * If a Mono source completes without value, all other sources are run to completion then - * the resulting {@link Mono} completes empty. - * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). - * - *

- * - *

- * @param p1 The first upstream {@link Publisher} to subscribe to. - * @param p2 The second upstream {@link Publisher} to subscribe to. - * @param p3 The third upstream {@link Publisher} to subscribe to. - * @param p4 The fourth upstream {@link Publisher} to subscribe to. - * @param p5 The fifth upstream {@link Publisher} to subscribe to. - * @param p6 The sixth upstream {@link Publisher} to subscribe to. - * @param p7 The seventh upstream {@link Publisher} to subscribe to. - * @param type of the value from p1 - * @param type of the value from p2 - * @param type of the value from p3 - * @param type of the value from p4 - * @param type of the value from p5 - * @param type of the value from p6 - * @param type of the value from p7 - * - * @return a {@link Mono}. - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static Mono> zipDelayError(Mono p1, - Mono p2, - Mono p3, - Mono p4, - Mono p5, - Mono p6, - Mono p7) { - return onAssembly(new MonoZip(true, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5, p6, p7)); - } - - /** - * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} - * have produced an item, aggregating their values into a {@link Tuple8} and delaying errors. - * If a Mono source completes without value, all other sources are run to completion then - * the resulting {@link Mono} completes empty. - * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). - * - *

- * - *

- * @param p1 The first upstream {@link Publisher} to subscribe to. - * @param p2 The second upstream {@link Publisher} to subscribe to. - * @param p3 The third upstream {@link Publisher} to subscribe to. - * @param p4 The fourth upstream {@link Publisher} to subscribe to. - * @param p5 The fifth upstream {@link Publisher} to subscribe to. - * @param p6 The sixth upstream {@link Publisher} to subscribe to. - * @param p7 The seventh upstream {@link Publisher} to subscribe to. - * @param p8 The eight upstream {@link Publisher} to subscribe to. - * @param type of the value from p1 - * @param type of the value from p2 - * @param type of the value from p3 - * @param type of the value from p4 - * @param type of the value from p5 - * @param type of the value from p6 - * @param type of the value from p7 - * @param type of the value from p8 - * - * @return a {@link Mono}. - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static Mono> zipDelayError(Mono p1, - Mono p2, - Mono p3, - Mono p4, - Mono p5, - Mono p6, - Mono p7, - Mono p8) { - return onAssembly(new MonoZip(true, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5, p6, p7, p8)); - } - - /** - * Aggregate given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal - * Monos} have produced an item. Errors from the sources are delayed. - * If a Mono source completes without value, all other sources are run to completion then - * the resulting {@link Mono} completes empty. - * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). - *

- * - *

- * - * @param monos The monos to use. - * @param combinator the function to transform the combined array into an arbitrary - * object. - * @param the combined result - * - * @return a {@link Mono}. - */ - public static Mono zipDelayError(final Iterable> monos, Function combinator) { - return onAssembly(new MonoZip<>(true, combinator, monos)); - } - - /** - * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the - * given {@literal Monos} have produced an item, aggregating their values according to - * the provided combinator function and delaying errors. - * If a Mono source completes without value, all other sources are run to completion then - * the resulting {@link Mono} completes empty. - * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). - * - *

- * - *

- * @param monos The monos to use. - * @param combinator the function to transform the combined array into an arbitrary - * object. - * @param the combined result - * - * @return a combined {@link Mono}. - */ - public static Mono zipDelayError(Function - combinator, Mono... monos) { - if (monos.length == 0) { - return empty(); - } - if (monos.length == 1) { - return monos[0].map(d -> combinator.apply(new Object[]{d})); - } - return onAssembly(new MonoZip<>(true, combinator, monos)); - } - -// ============================================================================================================== -// Operators -// ============================================================================================================== - - /** - * Transform this {@link Mono} into a target type. - * - *

-	 * {@code mono.as(Flux::from).subscribe() }
-	 * 
- * - * @param transformer the {@link Function} to immediately map this {@link Mono} - * into a target type - * @param

the returned instance type - * - * @return the {@link Mono} transformed to an instance of P - * @see #transformDeferred(Function) transformDeferred(Function) for a lazy transformation of Mono - */ - public final

P as(Function, P> transformer) { - return transformer.apply(this); - } - - /** - * Join the termination signals from this mono and another source into the returned - * void mono - * - *

- * - *

- * @param other the {@link Publisher} to wait for - * complete - * @return a new combined Mono - * @see #when - */ - public final Mono and(Publisher other) { - if (this instanceof MonoWhen) { - @SuppressWarnings("unchecked") MonoWhen o = (MonoWhen) this; - Mono result = o.whenAdditionalSource(other); - if (result != null) { - return result; - } - } - - return when(this, other); - } - - /** - * Subscribe to this {@link Mono} and block indefinitely until a next signal is - * received. Returns that value, or null if the Mono completes empty. In case the Mono - * errors, the original exception is thrown (wrapped in a {@link RuntimeException} if - * it was a checked exception). - * - *

- * - *

- * Note that each block() will trigger a new subscription: in other words, the result - * might miss signal from hot publishers. - * - * @return T the result - */ - @Nullable - public T block() { - BlockingMonoSubscriber subscriber = new BlockingMonoSubscriber<>(); - subscribe((Subscriber) subscriber); - return subscriber.blockingGet(); - } - - /** - * Subscribe to this {@link Mono} and block until a next signal is - * received or a timeout expires. Returns that value, or null if the Mono completes - * empty. In case the Mono errors, the original exception is thrown (wrapped in a - * {@link RuntimeException} if it was a checked exception). - * If the provided timeout expires, a {@link RuntimeException} is thrown. - * - *

- * - *

- * Note that each block() will trigger a new subscription: in other words, the result - * might miss signal from hot publishers. - * - * @param timeout maximum time period to wait for before raising a {@link RuntimeException} - * - * @return T the result - */ - @Nullable - public T block(Duration timeout) { - BlockingMonoSubscriber subscriber = new BlockingMonoSubscriber<>(); - subscribe((Subscriber) subscriber); - return subscriber.blockingGet(timeout.toNanos(), TimeUnit.NANOSECONDS); - } - - /** - * Subscribe to this {@link Mono} and block indefinitely until a next signal is - * received or the Mono completes empty. Returns an {@link Optional}, which can be used - * to replace the empty case with an Exception via {@link Optional#orElseThrow(Supplier)}. - * In case the Mono itself errors, the original exception is thrown (wrapped in a - * {@link RuntimeException} if it was a checked exception). - * - *

- * - *

- * Note that each blockOptional() will trigger a new subscription: in other words, the result - * might miss signal from hot publishers. - * - * @return T the result - */ - public Optional blockOptional() { - BlockingOptionalMonoSubscriber subscriber = new BlockingOptionalMonoSubscriber<>(); - subscribe((Subscriber) subscriber); - return subscriber.blockingGet(); - } - - /** - * Subscribe to this {@link Mono} and block until a next signal is - * received, the Mono completes empty or a timeout expires. Returns an {@link Optional} - * for the first two cases, which can be used to replace the empty case with an - * Exception via {@link Optional#orElseThrow(Supplier)}. - * In case the Mono itself errors, the original exception is thrown (wrapped in a - * {@link RuntimeException} if it was a checked exception). - * If the provided timeout expires, a {@link RuntimeException} is thrown. - * - *

- * - *

- * Note that each block() will trigger a new subscription: in other words, the result - * might miss signal from hot publishers. - * - * @param timeout maximum time period to wait for before raising a {@link RuntimeException} - * - * @return T the result - */ - public Optional blockOptional(Duration timeout) { - BlockingOptionalMonoSubscriber subscriber = new BlockingOptionalMonoSubscriber<>(); - subscribe((Subscriber) subscriber); - return subscriber.blockingGet(timeout.toNanos(), TimeUnit.NANOSECONDS); - } - - /** - * Cast the current {@link Mono} produced type into a target produced type. - * - *

- * - * - * @param the {@link Mono} output type - * @param clazz the target type to cast to - * - * @return a casted {@link Mono} - */ - public final Mono cast(Class clazz) { - Objects.requireNonNull(clazz, "clazz"); - return map(clazz::cast); - } - - /** - * Turn this {@link Mono} into a hot source and cache last emitted signals for further {@link Subscriber}. - * Completion and Error will also be replayed. - *

- * - *

- * Once the first subscription is made to this {@link Mono}, the source is subscribed to and - * the signal will be cached, indefinitely. This process cannot be cancelled. - *

- * In the face of multiple concurrent subscriptions, this operator ensures that only one - * subscription is made to the source. - * - * @return a replaying {@link Mono} - */ - public final Mono cache() { - return onAssembly(new MonoCacheTime<>(this)); - } - - /** - * Turn this {@link Mono} into a hot source and cache last emitted signals for further - * {@link Subscriber}, with an expiry timeout. - *

- * Completion and Error will also be replayed until {@code ttl} triggers in which case - * the next {@link Subscriber} will start over a new subscription. - *

- * - *

- * Cache loading (ie. subscription to the source) is triggered atomically by the first - * subscription to an uninitialized or expired cache, which guarantees that a single - * cache load happens at a time (and other subscriptions will get notified of the newly - * cached value when it arrives). - * - * @return a replaying {@link Mono} - */ - public final Mono cache(Duration ttl) { - return cache(ttl, Schedulers.parallel()); - } - - /** - * Turn this {@link Mono} into a hot source and cache last emitted signals for further - * {@link Subscriber}, with an expiry timeout. - *

- * Completion and Error will also be replayed until {@code ttl} triggers in which case - * the next {@link Subscriber} will start over a new subscription. - *

- * - *

- * Cache loading (ie. subscription to the source) is triggered atomically by the first - * subscription to an uninitialized or expired cache, which guarantees that a single - * cache load happens at a time (and other subscriptions will get notified of the newly - * cached value when it arrives). - * - * @param ttl Time-to-live for each cached item and post termination. - * @param timer the {@link Scheduler} on which to measure the duration. - * - * @return a replaying {@link Mono} - */ - public final Mono cache(Duration ttl, Scheduler timer) { - return onAssembly(new MonoCacheTime<>(this, ttl, timer)); - } - - /** - * Turn this {@link Mono} into a hot source and cache last emitted signal for further - * {@link Subscriber}, with an expiry timeout (TTL) that depends on said signal. - * A TTL of {@link Long#MAX_VALUE} milliseconds is interpreted as indefinite caching of - * the signal (no cache cleanup is scheduled, so the signal is retained as long as this - * {@link Mono} is not garbage collected). - *

- * Empty completion and Error will also be replayed according to their respective TTL, - * so transient errors can be "retried" by letting the {@link Function} return - * {@link Duration#ZERO}. Such a transient exception would then be propagated to the first - * subscriber but the following subscribers would trigger a new source subscription. - *

- * Exceptions in the TTL generators themselves are processed like the {@link Duration#ZERO} - * case, except the original signal is {@link Exceptions#addSuppressed(Throwable, Throwable) suppressed} - * (in case of onError) or {@link Hooks#onNextDropped(Consumer) dropped} - * (in case of onNext). - *

- * Note that subscribers that come in perfectly simultaneously could receive the same - * cached signal even if the TTL is set to zero. - *

- * Cache loading (ie. subscription to the source) is triggered atomically by the first - * subscription to an uninitialized or expired cache, which guarantees that a single - * cache load happens at a time (and other subscriptions will get notified of the newly - * cached value when it arrives). - * - * @param ttlForValue the TTL-generating {@link Function} invoked when source is valued - * @param ttlForError the TTL-generating {@link Function} invoked when source is erroring - * @param ttlForEmpty the TTL-generating {@link Supplier} invoked when source is empty - * @return a replaying {@link Mono} - */ - public final Mono cache(Function ttlForValue, - Function ttlForError, - Supplier ttlForEmpty) { - return cache(ttlForValue, ttlForError, ttlForEmpty, Schedulers.parallel()); - } - - /** - * Turn this {@link Mono} into a hot source and cache last emitted signal for further - * {@link Subscriber}, with an expiry timeout (TTL) that depends on said signal. - * A TTL of {@link Long#MAX_VALUE} milliseconds is interpreted as indefinite caching of - * the signal (no cache cleanup is scheduled, so the signal is retained as long as this - * {@link Mono} is not garbage collected). - *

- * Empty completion and Error will also be replayed according to their respective TTL, - * so transient errors can be "retried" by letting the {@link Function} return - * {@link Duration#ZERO}. Such a transient exception would then be propagated to the first - * subscriber but the following subscribers would trigger a new source subscription. - *

- * Exceptions in the TTL generators themselves are processed like the {@link Duration#ZERO} - * case, except the original signal is {@link Exceptions#addSuppressed(Throwable, Throwable) suppressed} - * (in case of onError) or {@link Hooks#onNextDropped(Consumer) dropped} - * (in case of onNext). - *

- * Note that subscribers that come in perfectly simultaneously could receive the same - * cached signal even if the TTL is set to zero. - *

- * Cache loading (ie. subscription to the source) is triggered atomically by the first - * subscription to an uninitialized or expired cache, which guarantees that a single - * cache load happens at a time (and other subscriptions will get notified of the newly - * cached value when it arrives). - * - * @param ttlForValue the TTL-generating {@link Function} invoked when source is valued - * @param ttlForError the TTL-generating {@link Function} invoked when source is erroring - * @param ttlForEmpty the TTL-generating {@link Supplier} invoked when source is empty - * @param timer the {@link Scheduler} on which to measure the duration. - * @return a replaying {@link Mono} - */ - public final Mono cache(Function ttlForValue, - Function ttlForError, - Supplier ttlForEmpty, - Scheduler timer) { - return onAssembly(new MonoCacheTime<>(this, ttlForValue, ttlForError, ttlForEmpty, timer)); - } - - /** - * Cache {@link Subscriber#onNext(Object) onNext} signal received from the source and replay it to other subscribers, - * while allowing invalidation by verifying the cached value against the given {@link Predicate} each time a late - * subscription occurs. - * Note that the {@link Predicate} is only evaluated if the cache is currently populated, ie. it is not applied - * upon receiving the source {@link Subscriber#onNext(Object) onNext} signal. - * For late subscribers, if the predicate returns {@code true} the cache is invalidated and a new subscription is made - * to the source in an effort to refresh the cache with a more up-to-date value to be passed to the new subscriber. - *

- * The predicate is not strictly evaluated once per downstream subscriber. Rather, subscriptions happening in concurrent - * batches will trigger a single evaluation of the predicate. Similarly, a batch of subscriptions happening before - * the cache is populated (ie. before this operator receives an onNext signal after an invalidation) will always - * receive the incoming value without going through the {@link Predicate}. The predicate is only triggered by - * subscribers that come in AFTER the cache is populated. Therefore, it is possible that pre-population subscribers - * receive an "invalid" value, especially if the object can switch from a valid to an invalid state in a short amount - * of time (eg. between creation, cache population and propagation to the downstream subscriber(s)). - *

- * If the cached value needs to be discarded in case of invalidation, the recommended way is to do so in the predicate - * directly. Note that some downstream subscribers might still be using or storing the value, for example if they - * haven't requested anything yet. - *

- * As this form of caching is explicitly value-oriented, empty source completion signals and error signals are NOT - * cached. It is always possible to use {@link #materialize()} to cache these (further using {@link #filter(Predicate)} - * if one wants to only consider empty sources or error sources). - *

- * Predicate is applied differently depending on whether the cache is populated or not: - *

    - *
  • IF EMPTY - *
    • first incoming subscriber creates a new COORDINATOR and adds itself
    - *
  • - *
  • IF COORDINATOR - *
      - *
    1. each incoming subscriber is added to the current "batch" (COORDINATOR)
    2. - *
    3. once the value is received, the predicate is applied ONCE - *
        - *
      1. mismatch: all the batch is terminated with an error - * -> we're back to init state, next subscriber will trigger a new coordinator and a new subscription
      2. - *
      3. ok: all the batch is completed with the value -> cache is now POPULATED
      4. - *
      - *
    4. - *
    - *
  • - *
  • IF POPULATED - *
      - *
    1. each incoming subscriber causes the predicate to apply
    2. - *
    3. if ok: complete that subscriber with the value
    4. - *
    5. if mismatch, swap the current POPULATED with a new COORDINATOR and add the subscriber to that coordinator
    6. - *
    7. imagining a race between sub1 and sub2: - *
        - *
      1. OK NOK will naturally lead to sub1 completing and sub2 being put on wait inside a new COORDINATOR
      2. - *
      3. NOK NOK will race swap of POPULATED with COORDINATOR1 and COORDINATOR2 respectively - *
          - *
        1. if sub1 swaps, sub2 will dismiss the COORDINATOR2 it failed to swap and loop back, see COORDINATOR1 and add itself
        2. - *
        3. if sub2 swaps, the reverse happens
        4. - *
        5. if value is populated in the time it takes for sub2 to loop back, sub2 sees a value and triggers the predicate again (hopefully passing)
        6. - *
        - *
      4. - *
      - *
    8. - *
    - *
  • - *
- *

- * Cancellation is only possible for downstream subscribers when they've been added to a COORDINATOR. - * Subscribers that are received when POPULATED will either be completed right away or (if the predicate fails) end up being added to a COORDINATOR. - *

- * When cancelling a COORDINATOR-issued subscription: - *

    - *
  1. removes itself from batch
  2. - *
  3. if 0 subscribers remaining - *
      - *
    1. swap COORDINATOR with EMPTY
    2. - *
    3. COORDINATOR cancels its source
    4. - *
    - *
  4. - *
- *

- * The fact that COORDINATOR cancels its source when no more subscribers remain is important, because it prevents issues with a never() source - * or a source that never produces a value passing the predicate (assuming timeouts on the subscriber). - * - * @param invalidationPredicate the {@link Predicate} used for cache invalidation. Returning {@code true} means the value is invalid and should be - * removed from the cache. - * @return a new cached {@link Mono} which can be invalidated - */ - public final Mono cacheInvalidateIf(Predicate invalidationPredicate) { - return onAssembly(new MonoCacheInvalidateIf<>(this, invalidationPredicate)); - } - - /** - * Cache {@link Subscriber#onNext(Object) onNext} signal received from the source and replay it to other subscribers, - * while allowing invalidation via a {@link Mono Mono<Void>} companion trigger generated from the currently - * cached value. - *

- * As this form of caching is explicitly value-oriented, empty source completion signals and error signals are NOT - * cached. It is always possible to use {@link #materialize()} to cache these (further using {@link #filter(Predicate)} - * if one wants to only consider empty sources or error sources). The exception is still propagated to the subscribers - * that have accumulated between the time the source has been subscribed to and the time the onError/onComplete terminal - * signal is received. An empty source is turned into a {@link NoSuchElementException} onError. - *

- * Completion of the trigger will invalidate the cached element, so the next subscriber that comes in will trigger - * a new subscription to the source, re-populating the cache and re-creating a new trigger out of that value. - *

- *

    - *
  • - * If the trigger completes with an error, all registered subscribers are terminated with the same error. - *
  • - *
  • - * If all the subscribers are cancelled before the cache is populated (ie. an attempt to - * cache a {@link Mono#never()}), the source subscription is cancelled. - *
  • - *
  • - * Cancelling a downstream subscriber once the cache has been populated is not necessarily relevant, - * as the value will be immediately replayed on subscription, which usually means within onSubscribe (so - * earlier than any cancellation can happen). That said the operator will make best efforts to detect such - * cancellations and avoid propagating the value to these subscribers. - *
  • - *
- *

- * If the cached value needs to be discarded in case of invalidation, use the {@link #cacheInvalidateWhen(Function, Consumer)} version. - * Note that some downstream subscribers might still be using or storing the value, for example if they - * haven't requested anything yet. - *

- * Trigger is generated only after a subscribers in the COORDINATOR have received the value, and only once. - * The only way to get out of the POPULATED state is to use the trigger, so there cannot be multiple trigger subscriptions, nor concurrent triggering. - *

- * Cancellation is only possible for downstream subscribers when they've been added to a COORDINATOR. - * Subscribers that are received when POPULATED will either be completed right away or (if the predicate fails) end up being added to a COORDINATOR. - *

- * When cancelling a COORDINATOR-issued subscription: - *

    - *
  1. removes itself from batch
  2. - *
  3. if 0 subscribers remaining - *
      - *
    1. swap COORDINATOR with EMPTY
    2. - *
    3. COORDINATOR cancels its source
    4. - *
    - *
  4. - *
- *

- * The fact that COORDINATOR cancels its source when no more subscribers remain is important, because it prevents issues with a never() source - * or a source that never produces a value passing the predicate (assuming timeouts on the subscriber). - * - * @param invalidationTriggerGenerator the {@link Function} that generates new {@link Mono Mono<Void>} triggers - * used for invalidation - * @return a new cached {@link Mono} which can be invalidated - */ - public final Mono cacheInvalidateWhen(Function> invalidationTriggerGenerator) { - return onAssembly(new MonoCacheInvalidateWhen<>(this, invalidationTriggerGenerator, null)); - } - - /** - * Cache {@link Subscriber#onNext(Object) onNext} signal received from the source and replay it to other subscribers, - * while allowing invalidation via a {@link Mono Mono<Void>} companion trigger generated from the currently - * cached value. - *

- * As this form of caching is explicitly value-oriented, empty source completion signals and error signals are NOT - * cached. It is always possible to use {@link #materialize()} to cache these (further using {@link #filter(Predicate)} - * if one wants to only consider empty sources or error sources). The exception is still propagated to the subscribers - * that have accumulated between the time the source has been subscribed to and the time the onError/onComplete terminal - * signal is received. An empty source is turned into a {@link NoSuchElementException} onError. - *

- * Completion of the trigger will invalidate the cached element, so the next subscriber that comes in will trigger - * a new subscription to the source, re-populating the cache and re-creating a new trigger out of that value. - *

- *

    - *
  • - * If the trigger completes with an error, all registered subscribers are terminated with the same error. - *
  • - *
  • - * If all the subscribers are cancelled before the cache is populated (ie. an attempt to - * cache a {@link Mono#never()}), the source subscription is cancelled. - *
  • - *
  • - * Cancelling a downstream subscriber once the cache has been populated is not necessarily relevant, - * as the value will be immediately replayed on subscription, which usually means within onSubscribe (so - * earlier than any cancellation can happen). That said the operator will make best efforts to detect such - * cancellations and avoid propagating the value to these subscribers. - *
  • - *
- *

- * Once a cached value is invalidated, it is passed to the provided {@link Consumer} (which MUST complete normally). - * Note that some downstream subscribers might still be using or storing the value, for example if they - * haven't requested anything yet. - *

- * Trigger is generated only after a subscribers in the COORDINATOR have received the value, and only once. - * The only way to get out of the POPULATED state is to use the trigger, so there cannot be multiple trigger subscriptions, nor concurrent triggering. - *

- * Cancellation is only possible for downstream subscribers when they've been added to a COORDINATOR. - * Subscribers that are received when POPULATED will either be completed right away or (if the predicate fails) end up being added to a COORDINATOR. - *

- * When cancelling a COORDINATOR-issued subscription: - *

    - *
  1. removes itself from batch
  2. - *
  3. if 0 subscribers remaining - *
      - *
    1. swap COORDINATOR with EMPTY
    2. - *
    3. COORDINATOR cancels its source
    4. - *
    - *
  4. - *
- *

- * The fact that COORDINATOR cancels its source when no more subscribers remain is important, because it prevents issues with a never() source - * or a source that never produces a value passing the predicate (assuming timeouts on the subscriber). - * - * @param invalidationTriggerGenerator the {@link Function} that generates new {@link Mono Mono<Void>} triggers - * used for invalidation - * @param onInvalidate the {@link Consumer} that will be applied to cached value upon invalidation - * @return a new cached {@link Mono} which can be invalidated - */ - public final Mono cacheInvalidateWhen(Function> invalidationTriggerGenerator, - Consumer onInvalidate) { - return onAssembly(new MonoCacheInvalidateWhen<>(this, invalidationTriggerGenerator, onInvalidate)); - } - - /** - * Prepare this {@link Mono} so that subscribers will cancel from it on a - * specified - * {@link Scheduler}. - * - *

- * - * - * @param scheduler the {@link Scheduler} to signal cancel on - * - * @return a scheduled cancel {@link Mono} - */ - public final Mono cancelOn(Scheduler scheduler) { - return onAssembly(new MonoCancelOn<>(this, scheduler)); - } - - /** - * Activate traceback (full assembly tracing) for this particular {@link Mono}, in case of an error - * upstream of the checkpoint. Tracing incurs the cost of an exception stack trace - * creation. - *

- * It should be placed towards the end of the reactive chain, as errors - * triggered downstream of it cannot be observed and augmented with assembly trace. - *

- * The traceback is attached to the error as a {@link Throwable#getSuppressed() suppressed exception}. - * As such, if the error is a {@link Exceptions#isMultiple(Throwable) composite one}, the traceback - * would appear as a component of the composite. In any case, the traceback nature can be detected via - * {@link Exceptions#isTraceback(Throwable)}. - * - * @return the assembly tracing {@link Mono} - */ - public final Mono checkpoint() { - return checkpoint(null, true); - } - - /** - * Activate traceback (assembly marker) for this particular {@link Mono} by giving it a description that - * will be reflected in the assembly traceback in case of an error upstream of the - * checkpoint. Note that unlike {@link #checkpoint()}, this doesn't create a - * filled stack trace, avoiding the main cost of the operator. - * However, as a trade-off the description must be unique enough for the user to find - * out where this Mono was assembled. If you only want a generic description, and - * still rely on the stack trace to find the assembly site, use the - * {@link #checkpoint(String, boolean)} variant. - *

- * It should be placed towards the end of the reactive chain, as errors - * triggered downstream of it cannot be observed and augmented with assembly trace. - *

- * The traceback is attached to the error as a {@link Throwable#getSuppressed() suppressed exception}. - * As such, if the error is a {@link Exceptions#isMultiple(Throwable) composite one}, the traceback - * would appear as a component of the composite. In any case, the traceback nature can be detected via - * {@link Exceptions#isTraceback(Throwable)}. - * - * @param description a unique enough description to include in the light assembly traceback. - * @return the assembly marked {@link Mono} - */ - public final Mono checkpoint(String description) { - return checkpoint(Objects.requireNonNull(description), false); - } - - /** - * Activate traceback (full assembly tracing or the lighter assembly marking depending on the - * {@code forceStackTrace} option). - *

- * By setting the {@code forceStackTrace} parameter to {@literal true}, activate assembly - * tracing for this particular {@link Mono} and give it a description that - * will be reflected in the assembly traceback in case of an error upstream of the - * checkpoint. Note that unlike {@link #checkpoint(String)}, this will incur - * the cost of an exception stack trace creation. The description could for - * example be a meaningful name for the assembled mono or a wider correlation ID, - * since the stack trace will always provide enough information to locate where this - * Flux was assembled. - *

- * By setting {@code forceStackTrace} to {@literal false}, behaves like - * {@link #checkpoint(String)} and is subject to the same caveat in choosing the - * description. - *

- * It should be placed towards the end of the reactive chain, as errors - * triggered downstream of it cannot be observed and augmented with assembly marker. - *

- * The traceback is attached to the error as a {@link Throwable#getSuppressed() suppressed exception}. - * As such, if the error is a {@link Exceptions#isMultiple(Throwable) composite one}, the traceback - * would appear as a component of the composite. In any case, the traceback nature can be detected via - * {@link Exceptions#isTraceback(Throwable)}. - * - * @param description a description (must be unique enough if forceStackTrace is set - * to false). - * @param forceStackTrace false to make a light checkpoint without a stacktrace, true - * to use a stack trace. - * @return the assembly marked {@link Mono}. - */ - public final Mono checkpoint(@Nullable String description, boolean forceStackTrace) { - final AssemblySnapshot stacktrace; - if (!forceStackTrace) { - stacktrace = new CheckpointLightSnapshot(description); - } - else { - stacktrace = new CheckpointHeavySnapshot(description, Traces.callSiteSupplierFactory.get()); - } - - return new MonoOnAssembly<>(this, stacktrace); - } - - /** - * Concatenate emissions of this {@link Mono} with the provided {@link Publisher} - * (no interleave). - *

- * - * - * @param other the {@link Publisher} sequence to concat after this {@link Flux} - * - * @return a concatenated {@link Flux} - */ - public final Flux concatWith(Publisher other) { - return Flux.concat(this, other); - } - - /** - * If context-propagation library - * is on the classpath, this is a convenience shortcut to capture thread local values during the - * subscription phase and put them in the {@link Context} that is visible upstream of this operator. - *

- * As a result this operator should generally be used as close as possible to the end of - * the chain / subscription point. - *

- * If the {@link ContextView} visible upstream is not empty, a small subset of operators will automatically - * restore the context snapshot ({@link #handle(BiConsumer) handle}, {@link #tap(SignalListenerFactory) tap}). - * If context-propagation is not available at runtime, this operator simply returns the current {@link Mono} - * instance. - * - * @return a new {@link Flux} where context-propagation API has been used to capture entries and - * inject them into the {@link Context} - * @see #handle(BiConsumer) - * @see #tap(SignalListenerFactory) - */ - public final Mono contextCapture() { - if (!ContextPropagation.isContextPropagationAvailable()) { - return this; - } - return onAssembly(new MonoContextWrite<>(this, ContextPropagation.contextCapture())); - } - - /** - * Enrich the {@link Context} visible from downstream for the benefit of upstream - * operators, by making all values from the provided {@link ContextView} visible on top - * of pairs from downstream. - *

- * A {@link Context} (and its {@link ContextView}) is tied to a given subscription - * and is read by querying the downstream {@link Subscriber}. {@link Subscriber} that - * don't enrich the context instead access their own downstream's context. As a result, - * this operator conceptually enriches a {@link Context} coming from under it in the chain - * (downstream, by default an empty one) and makes the new enriched {@link Context} - * visible to operators above it in the chain. - * - * @param contextToAppend the {@link ContextView} to merge with the downstream {@link Context}, - * resulting in a new more complete {@link Context} that will be visible from upstream. - * - * @return a contextualized {@link Mono} - * @see ContextView - */ - public final Mono contextWrite(ContextView contextToAppend) { - return contextWrite(c -> c.putAll(contextToAppend)); - } - - /** - * Enrich the {@link Context} visible from downstream for the benefit of upstream - * operators, by applying a {@link Function} to the downstream {@link Context}. - *

- * The {@link Function} takes a {@link Context} for convenience, allowing to easily - * call {@link Context#put(Object, Object) write APIs} to return a new {@link Context}. - *

- * A {@link Context} (and its {@link ContextView}) is tied to a given subscription - * and is read by querying the downstream {@link Subscriber}. {@link Subscriber} that - * don't enrich the context instead access their own downstream's context. As a result, - * this operator conceptually enriches a {@link Context} coming from under it in the chain - * (downstream, by default an empty one) and makes the new enriched {@link Context} - * visible to operators above it in the chain. - * - * @param contextModifier the {@link Function} to apply to the downstream {@link Context}, - * resulting in a new more complete {@link Context} that will be visible from upstream. - * - * @return a contextualized {@link Mono} - * @see Context - */ - public final Mono contextWrite(Function contextModifier) { - return onAssembly(new MonoContextWrite<>(this, contextModifier)); - } - - /** - * Provide a default single value if this mono is completed without any data - * - *

- * - *

- * @param defaultV the alternate value if this sequence is empty - * - * @return a new {@link Mono} - * - * @see Flux#defaultIfEmpty(Object) - */ - public final Mono defaultIfEmpty(T defaultV) { - if (this instanceof Fuseable.ScalarCallable) { - try { - T v = block(); - if (v == null) { - return Mono.just(defaultV); - } - } - catch (Throwable e) { - //leave MonoError returns as this - } - return this; - } - return onAssembly(new MonoDefaultIfEmpty<>(this, defaultV)); - } - - /** - * Delay this {@link Mono} element ({@link Subscriber#onNext} signal) by a given - * duration. Empty Monos or error signals are not delayed. - * - *

- * - * - *

- * Note that the scheduler on which the Mono chain continues execution will be the - * {@link Schedulers#parallel() parallel} scheduler if the mono is valued, or the - * current scheduler if the mono completes empty or errors. - * - * @param delay duration by which to delay the {@link Subscriber#onNext} signal - * @return a delayed {@link Mono} - */ - public final Mono delayElement(Duration delay) { - return delayElement(delay, Schedulers.parallel()); - } - - /** - * Delay this {@link Mono} element ({@link Subscriber#onNext} signal) by a given - * {@link Duration}, on a particular {@link Scheduler}. Empty monos or error signals are not delayed. - * - *

- * - * - *

- * Note that the scheduler on which the mono chain continues execution will be the - * scheduler provided if the mono is valued, or the current scheduler if the mono - * completes empty or errors. - * - * @param delay {@link Duration} by which to delay the {@link Subscriber#onNext} signal - * @param timer a time-capable {@link Scheduler} instance to delay the value signal on - * @return a delayed {@link Mono} - */ - public final Mono delayElement(Duration delay, Scheduler timer) { - return onAssembly(new MonoDelayElement<>(this, delay.toNanos(), TimeUnit.NANOSECONDS, timer)); - } - - /** - * Subscribe to this {@link Mono} and another {@link Publisher} that is generated from - * this Mono's element and which will be used as a trigger for relaying said element. - *

- * That is to say, the resulting {@link Mono} delays until this Mono's element is - * emitted, generates a trigger Publisher and then delays again until the trigger - * Publisher terminates. - *

- * Note that contiguous calls to all delayUntil are fused together. - * The triggers are generated and subscribed to in sequence, once the previous trigger - * completes. Error is propagated immediately - * downstream. In both cases, an error in the source is immediately propagated. - *

- * - * - * @param triggerProvider a {@link Function} that maps this Mono's value into a - * {@link Publisher} whose termination will trigger relaying the value. - * - * @return this Mono, but delayed until the derived publisher terminates. - */ - public final Mono delayUntil(Function> triggerProvider) { - Objects.requireNonNull(triggerProvider, "triggerProvider required"); - if (this instanceof MonoDelayUntil) { - return ((MonoDelayUntil) this).copyWithNewTriggerGenerator(false,triggerProvider); - } - return onAssembly(new MonoDelayUntil<>(this, triggerProvider)); - } - - /** - * Delay the {@link Mono#subscribe(Subscriber) subscription} to this {@link Mono} source until the given - * period elapses. - * - *

- * - * - * @param delay duration before subscribing this {@link Mono} - * - * @return a delayed {@link Mono} - * - */ - public final Mono delaySubscription(Duration delay) { - return delaySubscription(delay, Schedulers.parallel()); - } - - /** - * Delay the {@link Mono#subscribe(Subscriber) subscription} to this {@link Mono} source until the given - * {@link Duration} elapses. - * - *

- * - * - * @param delay {@link Duration} before subscribing this {@link Mono} - * @param timer a time-capable {@link Scheduler} instance to run on - * - * @return a delayed {@link Mono} - * - */ - public final Mono delaySubscription(Duration delay, Scheduler timer) { - return delaySubscription(Mono.delay(delay, timer)); - } - - /** - * Delay the subscription to this {@link Mono} until another {@link Publisher} - * signals a value or completes. - * - *

- * - * - * @param subscriptionDelay a - * {@link Publisher} to signal by next or complete this {@link Mono#subscribe(Subscriber)} - * @param the other source type - * - * @return a delayed {@link Mono} - * - */ - public final Mono delaySubscription(Publisher subscriptionDelay) { - return onAssembly(new MonoDelaySubscription<>(this, subscriptionDelay)); - } - - /** - * An operator working only if this {@link Mono} emits onNext, onError or onComplete {@link Signal} - * instances, transforming these {@link #materialize() materialized} signals into - * real signals on the {@link Subscriber}. - * The error {@link Signal} will trigger onError and complete {@link Signal} will trigger - * onComplete. - * - *

- * - * - * @param the dematerialized type - * @return a dematerialized {@link Mono} - * @see #materialize() - */ - public final Mono dematerialize() { - @SuppressWarnings("unchecked") - Mono> thiz = (Mono>) this; - return onAssembly(new MonoDematerialize<>(thiz)); - } - - /** - * Add behavior (side-effect) triggered after the {@link Mono} terminates, either by - * completing downstream successfully or with an error. - *

- * - *

- * The relevant signal is propagated downstream, then the {@link Runnable} is executed. - * - * @param afterTerminate the callback to call after {@link Subscriber#onComplete} or {@link Subscriber#onError} - * - * @return an observed {@link Mono} - */ - public final Mono doAfterTerminate(Runnable afterTerminate) { - Objects.requireNonNull(afterTerminate, "afterTerminate"); - return onAssembly(new MonoPeekTerminal<>(this, null, null, (s, e) -> afterTerminate.run())); - } - - /** - * Add behavior (side-effect) triggered before the {@link Mono} is - * subscribed to, which should be the first event after assembly time. - *

- * - *

- * Note that when several {@link #doFirst(Runnable)} operators are used anywhere in a - * chain of operators, their order of execution is reversed compared to the declaration - * order (as subscribe signal flows backward, from the ultimate subscriber to the source - * publisher): - *


-	 * Mono.just(1v)
-	 *     .doFirst(() -> System.out.println("three"))
-	 *     .doFirst(() -> System.out.println("two"))
-	 *     .doFirst(() -> System.out.println("one"));
-	 * //would print one two three
-	 * 
-	 * 
- *

- * In case the {@link Runnable} throws an exception, said exception will be directly - * propagated to the subscribing {@link Subscriber} along with a no-op {@link Subscription}, - * similarly to what {@link #error(Throwable)} does. Otherwise, after the handler has - * executed, the {@link Subscriber} is directly subscribed to the original source - * {@link Mono} ({@code this}). - *

- * This side-effect method provides stronger first guarantees compared to - * {@link #doOnSubscribe(Consumer)}, which is triggered once the {@link Subscription} - * has been set up and passed to the {@link Subscriber}. - * - * @param onFirst the callback to execute before the {@link Mono} is subscribed to - * @return an observed {@link Mono} - */ - public final Mono doFirst(Runnable onFirst) { - Objects.requireNonNull(onFirst, "onFirst"); - if (this instanceof Fuseable) { - return onAssembly(new MonoDoFirstFuseable<>(this, onFirst)); - } - return onAssembly(new MonoDoFirst<>(this, onFirst)); - } - - /** - * Add behavior triggering after the {@link Mono} terminates for any reason, - * including cancellation. The terminating event ({@link SignalType#ON_COMPLETE}, - * {@link SignalType#ON_ERROR} and {@link SignalType#CANCEL}) is passed to the consumer, - * which is executed after the signal has been passed downstream. - *

- * Note that the fact that the signal is propagated downstream before the callback is - * executed means that several doFinally in a row will be executed in - * reverse order. If you want to assert the execution of the callback - * please keep in mind that the Mono will complete before it is executed, so its - * effect might not be visible immediately after eg. a {@link #block()}. - *

- * - * - * - * @param onFinally the callback to execute after a terminal signal (complete, error - * or cancel) - * @return an observed {@link Mono} - */ - public final Mono doFinally(Consumer onFinally) { - Objects.requireNonNull(onFinally, "onFinally"); - return onAssembly(new MonoDoFinally<>(this, onFinally)); - } - - /** - * Add behavior triggered when the {@link Mono} is cancelled. - *

- * - *

- * The handler is executed first, then the cancel signal is propagated upstream - * to the source. - * - * @param onCancel the callback to call on {@link Subscription#cancel()} - * - * @return a new {@link Mono} - */ - public final Mono doOnCancel(Runnable onCancel) { - Objects.requireNonNull(onCancel, "onCancel"); - return doOnSignal(this, null, null, null, onCancel); - } - - /** - * Potentially modify the behavior of the whole chain of operators upstream of this one to - * conditionally clean up elements that get discarded by these operators. - *

- * The {@code discardHook} MUST be idempotent and safe to use on any instance of the desired - * type. - * Calls to this method are additive, and the order of invocation of the {@code discardHook} - * is the same as the order of declaration (calling {@code .filter(...).doOnDiscard(first).doOnDiscard(second)} - * will let the filter invoke {@code first} then {@code second} handlers). - *

- * Two main categories of discarding operators exist: - *

    - *
  • filtering operators, dropping some source elements as part of their designed behavior
  • - *
  • operators that prefetch a few elements and keep them around pending a request, but get cancelled/in error
  • - *
- * WARNING: Not all operators support this instruction. The ones that do are identified in the javadoc by - * the presence of a Discard Support section. - * - * @param type the {@link Class} of elements in the upstream chain of operators that - * this cleanup hook should take into account. - * @param discardHook a {@link Consumer} of elements in the upstream chain of operators - * that performs the cleanup. - * @return a {@link Mono} that cleans up matching elements that get discarded upstream of it. - */ - public final Mono doOnDiscard(final Class type, final Consumer discardHook) { - return contextWrite(Operators.discardLocalAdapter(type, discardHook)); - } - - /** - * Add behavior triggered when the {@link Mono} emits a data successfully. - * - *

- * - *

- * The {@link Consumer} is executed first, then the onNext signal is propagated - * downstream. - * - * @param onNext the callback to call on {@link Subscriber#onNext} - * - * @return a new {@link Mono} - */ - public final Mono doOnNext(Consumer onNext) { - Objects.requireNonNull(onNext, "onNext"); - return doOnSignal(this, null, onNext, null, null); - } - - /** - * Add behavior triggered as soon as the {@link Mono} can be considered to have completed successfully. - * The value passed to the {@link Consumer} reflects the type of completion: - * - *

    - *
  • null : completed without data. handler is executed right before onComplete is propagated downstream
  • - *
  • T: completed with data. handler is executed right before onNext is propagated downstream
  • - *
- * - *

- * - *

- * The {@link Consumer} is executed before propagating either onNext or onComplete downstream. - * - * @param onSuccess the callback to call on, argument is null if the {@link Mono} - * completes without data - * {@link Subscriber#onNext} or {@link Subscriber#onComplete} without preceding {@link Subscriber#onNext} - * - * @return a new {@link Mono} - */ - public final Mono doOnSuccess(Consumer onSuccess) { - Objects.requireNonNull(onSuccess, "onSuccess"); - return doOnTerminalSignal(this, onSuccess, null, null); - } - - /** - * Add behavior triggered when the {@link Mono} emits an item, fails with an error - * or completes successfully. All these events are represented as a {@link Signal} - * that is passed to the side-effect callback. Note that this is an advanced operator, - * typically used for monitoring of a Mono. - * These {@link Signal} have a {@link Context} associated to them. - *

- * - *

- * The {@link Consumer} is executed first, then the relevant signal is propagated - * downstream. - * - * @param signalConsumer the mandatory callback to call on - * {@link Subscriber#onNext(Object)}, {@link Subscriber#onError(Throwable)} and - * {@link Subscriber#onComplete()} - * @return an observed {@link Mono} - * @see #doOnNext(Consumer) - * @see #doOnError(Consumer) - * @see #materialize() - * @see Signal - */ - public final Mono doOnEach(Consumer> signalConsumer) { - Objects.requireNonNull(signalConsumer, "signalConsumer"); - if (this instanceof Fuseable) { - return onAssembly(new MonoDoOnEachFuseable<>(this, signalConsumer)); - } - return onAssembly(new MonoDoOnEach<>(this, signalConsumer)); - - } - - /** - * Add behavior triggered when the {@link Mono} completes with an error. - * - *

- * - *

- * The {@link Consumer} is executed first, then the onError signal is propagated - * downstream. - * - * @param onError the error callback to call on {@link Subscriber#onError(Throwable)} - * - * @return a new {@link Mono} - */ - public final Mono doOnError(Consumer onError) { - Objects.requireNonNull(onError, "onError"); - return doOnTerminalSignal(this, null, onError, null); - } - - - /** - * Add behavior triggered when the {@link Mono} completes with an error matching the given exception type. - *

- * - *

- * The {@link Consumer} is executed first, then the onError signal is propagated - * downstream. - * - * @param exceptionType the type of exceptions to handle - * @param onError the error handler for relevant errors - * @param type of the error to handle - * - * @return an observed {@link Mono} - * - */ - public final Mono doOnError(Class exceptionType, - final Consumer onError) { - Objects.requireNonNull(exceptionType, "type"); - Objects.requireNonNull(onError, "onError"); - return doOnTerminalSignal(this, null, - error -> { - if (exceptionType.isInstance(error)) onError.accept(exceptionType.cast(error)); - }, - null); - } - - /** - * Add behavior triggered when the {@link Mono} completes with an error matching the given predicate. - *

- * - *

- * The {@link Consumer} is executed first, then the onError signal is propagated - * downstream. - * - * @param predicate the matcher for exceptions to handle - * @param onError the error handler for relevant error - * - * @return an observed {@link Mono} - * - */ - public final Mono doOnError(Predicate predicate, - final Consumer onError) { - Objects.requireNonNull(predicate, "predicate"); - Objects.requireNonNull(onError, "onError"); - return doOnTerminalSignal(this, null, - error -> { - if (predicate.test(error)) onError.accept(error); - }, - null); - } - /** - * Add behavior triggering a {@link LongConsumer} when the {@link Mono} receives any request. - *

- * Note that non fatal error raised in the callback will not be propagated and - * will simply trigger {@link Operators#onOperatorError(Throwable, Context)}. - * - *

- * - *

- * The {@link LongConsumer} is executed first, then the request signal is propagated - * upstream to the parent. - * - * @param consumer the consumer to invoke on each request - * - * @return an observed {@link Mono} - */ - public final Mono doOnRequest(final LongConsumer consumer) { - Objects.requireNonNull(consumer, "consumer"); - return doOnSignal(this, null, null, consumer, null); - } - - /** - * Add behavior (side-effect) triggered when the {@link Mono} is being subscribed, - * that is to say when a {@link Subscription} has been produced by the {@link Publisher} - * and is being passed to the {@link Subscriber#onSubscribe(Subscription)}. - *

- * This method is not intended for capturing the subscription and calling its methods, - * but for side effects like monitoring. For instance, the correct way to cancel a subscription is - * to call {@link Disposable#dispose()} on the Disposable returned by {@link Mono#subscribe()}. - *

- * - *

- * The {@link Consumer} is executed first, then the {@link Subscription} is propagated - * downstream to the next subscriber in the chain that is being established. - * - * @param onSubscribe the callback to call on {@link Subscriber#onSubscribe(Subscription)} - * - * @return a new {@link Mono} - * @see #doFirst(Runnable) - */ - public final Mono doOnSubscribe(Consumer onSubscribe) { - Objects.requireNonNull(onSubscribe, "onSubscribe"); - return doOnSignal(this, onSubscribe, null, null, null); - } - - /** - * Add behavior triggered when the {@link Mono} terminates, either by completing with a value, - * completing empty or failing with an error. Unlike in {@link Flux#doOnTerminate(Runnable)}, - * the simple fact that a {@link Mono} emits {@link Subscriber#onNext(Object) onNext} implies - * completion, so the handler is invoked BEFORE the element is propagated (same as with {@link #doOnSuccess(Consumer)}). - * - *

- *

- * The {@link Runnable} is executed first, then the onNext/onComplete/onError signal is propagated - * downstream. - * - * @param onTerminate the callback to call {@link Subscriber#onNext}, {@link Subscriber#onComplete} without preceding {@link Subscriber#onNext} or {@link Subscriber#onError} - * - * @return a new {@link Mono} - */ - public final Mono doOnTerminate(Runnable onTerminate) { - Objects.requireNonNull(onTerminate, "onTerminate"); - return doOnTerminalSignal(this, ignoreValue -> onTerminate.run(), ignoreError -> onTerminate.run(), null); - } - - /** - * Map this {@link Mono} into {@link reactor.util.function.Tuple2 Tuple2<Long, T>} - * of timemillis and source data. The timemillis corresponds to the elapsed time between - * the subscribe and the first next signal, as measured by the {@link Schedulers#parallel() parallel} scheduler. - * - *

- * - * - * @return a new {@link Mono} that emits a tuple of time elapsed in milliseconds and matching data - * @see #timed() - */ - public final Mono> elapsed() { - return elapsed(Schedulers.parallel()); - } - - /** - * Map this {@link Mono} sequence into {@link reactor.util.function.Tuple2 Tuple2<Long, T>} - * of timemillis and source data. The timemillis corresponds to the elapsed time between the subscribe and the first - * next signal, as measured by the provided {@link Scheduler}. - * - *

- * - * - * @param scheduler a {@link Scheduler} instance to read time from - * @return a new {@link Mono} that emits a tuple of time elapsed in milliseconds and matching data - * @see #timed(Scheduler) - */ - public final Mono> elapsed(Scheduler scheduler) { - Objects.requireNonNull(scheduler, "scheduler"); - return onAssembly(new MonoElapsed<>(this, scheduler)); - } - - /** - * Recursively expand elements into a graph and emit all the resulting element, - * in a depth-first traversal order. - *

- * That is: emit the value from this {@link Mono}, expand it and emit the first value - * at this first level of recursion, and so on... When no more recursion is possible, - * backtrack to the previous level and re-apply the strategy. - *

- * For example, given the hierarchical structure - *

-	 *  A
-	 *   - AA
-	 *     - aa1
-	 *   - AB
-	 *     - ab1
-	 *   - a1
-	 * 
- * - * Expands {@code Mono.just(A)} into - *
-	 *  A
-	 *  AA
-	 *  aa1
-	 *  AB
-	 *  ab1
-	 *  a1
-	 * 
- * - * @param expander the {@link Function} applied at each level of recursion to expand - * values into a {@link Publisher}, producing a graph. - * @param capacityHint a capacity hint to prepare the inner queues to accommodate n - * elements per level of recursion. - * - * @return this Mono expanded depth-first to a {@link Flux} - */ - public final Flux expandDeep(Function> expander, - int capacityHint) { - return Flux.onAssembly(new MonoExpand<>(this, expander, false, capacityHint)); - } - - /** - * Recursively expand elements into a graph and emit all the resulting element, - * in a depth-first traversal order. - *

- * That is: emit the value from this {@link Mono}, expand it and emit the first value - * at this first level of recursion, and so on... When no more recursion is possible, - * backtrack to the previous level and re-apply the strategy. - *

- * For example, given the hierarchical structure - *

-	 *  A
-	 *   - AA
-	 *     - aa1
-	 *   - AB
-	 *     - ab1
-	 *   - a1
-	 * 
- * - * Expands {@code Mono.just(A)} into - *
-	 *  A
-	 *  AA
-	 *  aa1
-	 *  AB
-	 *  ab1
-	 *  a1
-	 * 
- * - * @param expander the {@link Function} applied at each level of recursion to expand - * values into a {@link Publisher}, producing a graph. - * - * @return this Mono expanded depth-first to a {@link Flux} - */ - public final Flux expandDeep(Function> expander) { - return expandDeep(expander, Queues.SMALL_BUFFER_SIZE); - } - - /** - * Recursively expand elements into a graph and emit all the resulting element using - * a breadth-first traversal strategy. - *

- * That is: emit the value from this {@link Mono} first, then expand it at a first level of - * recursion and emit all of the resulting values, then expand all of these at a - * second level and so on... - *

- * For example, given the hierarchical structure - *

-	 *  A
-	 *   - AA
-	 *     - aa1
-	 *   - AB
-	 *     - ab1
-	 *   - a1
-	 * 
- * - * Expands {@code Mono.just(A)} into - *
-	 *  A
-	 *  AA
-	 *  AB
-	 *  a1
-	 *  aa1
-	 *  ab1
-	 * 
- * - * @param expander the {@link Function} applied at each level of recursion to expand - * values into a {@link Publisher}, producing a graph. - * @param capacityHint a capacity hint to prepare the inner queues to accommodate n - * elements per level of recursion. - * - * @return this Mono expanded breadth-first to a {@link Flux} - */ - public final Flux expand(Function> expander, - int capacityHint) { - return Flux.onAssembly(new MonoExpand<>(this, expander, true, capacityHint)); - } - - /** - * Recursively expand elements into a graph and emit all the resulting element using - * a breadth-first traversal strategy. - *

- * That is: emit the value from this {@link Mono} first, then expand it at a first level of - * recursion and emit all of the resulting values, then expand all of these at a - * second level and so on... - *

- * For example, given the hierarchical structure - *

-	 *  A
-	 *   - AA
-	 *     - aa1
-	 *   - AB
-	 *     - ab1
-	 *   - a1
-	 * 
- * - * Expands {@code Mono.just(A)} into - *
-	 *  A
-	 *  AA
-	 *  AB
-	 *  a1
-	 *  aa1
-	 *  ab1
-	 * 
- * - * @param expander the {@link Function} applied at each level of recursion to expand - * values into a {@link Publisher}, producing a graph. - * - * @return this Mono expanded breadth-first to a {@link Flux} - */ - public final Flux expand(Function> expander) { - return expand(expander, Queues.SMALL_BUFFER_SIZE); - } - - /** - * If this {@link Mono} is valued, test the result and replay it if predicate returns true. - * Otherwise complete without value. - * - *

- * - * - *

Discard Support: This operator discards the element if it does not match the filter. It - * also discards upon cancellation or error triggered by a data signal. - * - * @param tester the predicate to evaluate - * - * @return a filtered {@link Mono} - */ - public final Mono filter(final Predicate tester) { - if (this instanceof Fuseable) { - return onAssembly(new MonoFilterFuseable<>(this, tester)); - } - return onAssembly(new MonoFilter<>(this, tester)); - } - - /** - * If this {@link Mono} is valued, test the value asynchronously using a generated - * {@code Publisher} test. The value from the Mono is replayed if the - * first item emitted by the test is {@literal true}. It is dropped if the test is - * either empty or its first emitted value is {@literal false}. - *

- * Note that only the first value of the test publisher is considered, and unless it - * is a {@link Mono}, test will be cancelled after receiving that first value. - * - *

- * - * - *

Discard Support: This operator discards the element if it does not match the filter. It - * also discards upon cancellation or error triggered by a data signal. - * - * @param asyncPredicate the function generating a {@link Publisher} of {@link Boolean} - * to filter the Mono with - * - * @return a filtered {@link Mono} - */ - public final Mono filterWhen(Function> asyncPredicate) { - return onAssembly(new MonoFilterWhen<>(this, asyncPredicate)); - } - - /** - * Transform the item emitted by this {@link Mono} asynchronously, returning the - * value emitted by another {@link Mono} (possibly changing the value type). - * - *

- * - * - * @param transformer the function to dynamically bind a new {@link Mono} - * @param the result type bound - * - * @return a new {@link Mono} with an asynchronously mapped value. - */ - public final Mono flatMap(Function> - transformer) { - return onAssembly(new MonoFlatMap<>(this, transformer)); - } - - /** - * Transform the item emitted by this {@link Mono} into a Publisher, then forward - * its emissions into the returned {@link Flux}. - * - *

- * - * - * @param mapper the - * {@link Function} to produce a sequence of R from the eventual passed {@link Subscriber#onNext} - * @param the merged sequence type - * - * @return a new {@link Flux} as the sequence is not guaranteed to be single at most - */ - public final Flux flatMapMany(Function> mapper) { - return Flux.onAssembly(new MonoFlatMapMany<>(this, mapper)); - } - - /** - * Transform the signals emitted by this {@link Mono} into signal-specific Publishers, - * then forward the applicable Publisher's emissions into the returned {@link Flux}. - * - *

- * - * - * @param mapperOnNext the {@link Function} to call on next data and returning a sequence to merge - * @param mapperOnError the {@link Function} to call on error signal and returning a sequence to merge - * @param mapperOnComplete the {@link Function} to call on complete signal and returning a sequence to merge - * @param the type of the produced inner sequence - * - * @return a new {@link Flux} as the sequence is not guaranteed to be single at most - * - * @see Flux#flatMap(Function, Function, Supplier) - */ - public final Flux flatMapMany(Function> mapperOnNext, - Function> mapperOnError, - Supplier> mapperOnComplete) { - return flux().flatMap(mapperOnNext, mapperOnError, mapperOnComplete); - } - - /** - * Transform the item emitted by this {@link Mono} into {@link Iterable}, then forward - * its elements into the returned {@link Flux}. - * The {@link Iterable#iterator()} method will be called at least once and at most twice. - * - *

- * - *

- * This operator inspects each {@link Iterable}'s {@link Spliterator} to assess if the iteration - * can be guaranteed to be finite (see {@link Operators#onDiscardMultiple(Iterator, boolean, Context)}). - * Since the default Spliterator wraps the Iterator we can have two {@link Iterable#iterator()} - * calls per iterable. This second invocation is skipped on a {@link Collection } however, a type which is - * assumed to be always finite. - * - *

Discard Support: Upon cancellation, this operator discards {@code T} elements it prefetched and, in - * some cases, attempts to discard remainder of the currently processed {@link Iterable} (if it can - * safely ensure the iterator is finite). Note that this means each {@link Iterable}'s {@link Iterable#iterator()} - * method could be invoked twice. - * - * @param mapper the {@link Function} to transform input item into a sequence {@link Iterable} - * @param the merged output sequence type - * - * @return a merged {@link Flux} - * - */ - public final Flux flatMapIterable(Function> mapper) { - return Flux.onAssembly(new MonoFlattenIterable<>(this, mapper, Integer - .MAX_VALUE, Queues.one())); - } - - /** - * Convert this {@link Mono} to a {@link Flux} - * - * @return a {@link Flux} variant of this {@link Mono} - */ - public final Flux flux() { - if (this instanceof Callable && !(this instanceof Fuseable.ScalarCallable)) { - @SuppressWarnings("unchecked") Callable thiz = (Callable) this; - return Flux.onAssembly(new FluxCallable<>(thiz)); - } - return Flux.from(this); - } - - /** - * Emit a single boolean true if this {@link Mono} has an element. - * - *

- * - * - * @return a new {@link Mono} with true if a value is emitted and false - * otherwise - */ - public final Mono hasElement() { - return onAssembly(new MonoHasElement<>(this)); - } - - /** - * Handle the items emitted by this {@link Mono} by calling a biconsumer with the - * output sink for each onNext. At most one {@link SynchronousSink#next(Object)} - * call must be performed and/or 0 or 1 {@link SynchronousSink#error(Throwable)} or - * {@link SynchronousSink#complete()}. - *

- * When the context-propagation library - * is available at runtime and the downstream {@link ContextView} is not empty, this operator implicitly uses the - * library to restore thread locals around the handler {@link BiConsumer}. Typically, this would be done in conjunction - * with the use of {@link #contextCapture()} operator down the chain. - * - * @param handler the handling {@link BiConsumer} - * @param the transformed type - * - * @return a transformed {@link Mono} - */ - public final Mono handle(BiConsumer> handler) { - if (this instanceof Fuseable) { - return onAssembly(new MonoHandleFuseable<>(this, handler)); - } - return onAssembly(new MonoHandle<>(this, handler)); - } - - /** - * Hides the identity of this {@link Mono} instance. - * - *

The main purpose of this operator is to prevent certain identity-based - * optimizations from happening, mostly for diagnostic purposes. - * - * @return a new {@link Mono} preventing {@link Publisher} / {@link Subscription} based Reactor optimizations - */ - public final Mono hide() { - return onAssembly(new MonoHide<>(this)); - } - - /** - * Ignores onNext signal (dropping it) and only propagates termination events. - * - *

- * - *

- * - *

Discard Support: This operator discards the source element. - * - * @return a new empty {@link Mono} representing the completion of this {@link Mono}. - */ - public final Mono ignoreElement() { - return onAssembly(new MonoIgnoreElement<>(this)); - } - - /** - * Observe all Reactive Streams signals and trace them using {@link Logger} support. - * Default will use {@link Level#INFO} and {@code java.util.logging}. - * If SLF4J is available, it will be used instead. - * - *

- * - *

- * The default log category will be "reactor.Mono", followed by a suffix generated from - * the source operator, e.g. "reactor.Mono.Map". - * - * @return a new {@link Mono} that logs signals - * - * @see Flux#log() - */ - public final Mono log() { - return log(null, Level.INFO); - } - - /** - * Observe all Reactive Streams signals and use {@link Logger} support to handle trace implementation. Default will - * use {@link Level#INFO} and java.util.logging. If SLF4J is available, it will be used instead. - * - *

- * - * - * @param category to be mapped into logger configuration (e.g. org.springframework - * .reactor). If category ends with "." like "reactor.", a generated operator - * suffix will complete, e.g. "reactor.Flux.Map". - * - * @return a new {@link Mono} - */ - public final Mono log(@Nullable String category) { - return log(category, Level.INFO); - } - - /** - * Observe Reactive Streams signals matching the passed flags {@code options} and use - * {@link Logger} support to handle trace implementation. Default will use the passed - * {@link Level} and java.util.logging. If SLF4J is available, it will be used instead. - * - * Options allow fine grained filtering of the traced signal, for instance to only capture onNext and onError: - *

-	 *     mono.log("category", SignalType.ON_NEXT, SignalType.ON_ERROR)
-	 * 
- *

- * - * - * @param category to be mapped into logger configuration (e.g. org.springframework - * .reactor). If category ends with "." like "reactor.", a generated operator - * suffix will complete, e.g. "reactor.Flux.Map". - * @param level the {@link Level} to enforce for this tracing Mono (only FINEST, FINE, - * INFO, WARNING and SEVERE are taken into account) - * @param options a vararg {@link SignalType} option to filter log messages - * - * @return a new {@link Mono} - * - */ - public final Mono log(@Nullable String category, Level level, SignalType... options) { - return log(category, level, false, options); - } - - /** - * Observe Reactive Streams signals matching the passed filter {@code options} and - * use {@link Logger} support to - * handle trace - * implementation. Default will - * use the passed {@link Level} and java.util.logging. If SLF4J is available, it will be used instead. - * - * Options allow fine grained filtering of the traced signal, for instance to only capture onNext and onError: - *

-	 *     mono.log("category", Level.INFO, SignalType.ON_NEXT, SignalType.ON_ERROR)
-	 * 
- *

- * - * - * @param category to be mapped into logger configuration (e.g. org.springframework - * .reactor). If category ends with "." like "reactor.", a generated operator - * suffix will complete, e.g. "reactor.Mono.Map". - * @param level the {@link Level} to enforce for this tracing Mono (only FINEST, FINE, - * INFO, WARNING and SEVERE are taken into account) - * @param showOperatorLine capture the current stack to display operator - * class/line number. - * @param options a vararg {@link SignalType} option to filter log messages - * - * @return a new unaltered {@link Mono} - */ - public final Mono log(@Nullable String category, - Level level, - boolean showOperatorLine, - SignalType... options) { - SignalLogger log = new SignalLogger<>(this, category, level, - showOperatorLine, options); - - if (this instanceof Fuseable) { - return onAssembly(new MonoLogFuseable<>(this, log)); - } - return onAssembly(new MonoLog<>(this, log)); - } - - - /** - * Observe Reactive Streams signals matching the passed filter {@code options} and - * trace them using a specific user-provided {@link Logger}, at {@link Level#INFO} level. - *

- * - * - * @param logger the {@link Logger} to use, instead of resolving one through a category. - * - * @return a new {@link Mono} that logs signals - */ - public final Mono log(Logger logger) { - return log(logger, Level.INFO, false); - } - - /** - * Observe Reactive Streams signals matching the passed filter {@code options} and - * trace them using a specific user-provided {@link Logger}, at the given {@link Level}. - *

- * Options allow fine grained filtering of the traced signal, for instance to only - * capture onNext and onError: - *

-	 *     flux.log(myCustomLogger, Level.INFO, SignalType.ON_NEXT, SignalType.ON_ERROR)
-	 * 
- *

- * - * - * @param logger the {@link Logger} to use, instead of resolving one through a category. - * @param level the {@link Level} to enforce for this tracing Flux (only FINEST, FINE, - * INFO, WARNING and SEVERE are taken into account) - * @param showOperatorLine capture the current stack to display operator class/line number. - * @param options a vararg {@link SignalType} option to filter log messages - * - * @return a new {@link Mono} that logs signals - */ - public final Mono log(Logger logger, - Level level, - boolean showOperatorLine, - SignalType... options) { - SignalLogger log = new SignalLogger<>(this, "IGNORED", level, - showOperatorLine, - s -> logger, - options); - - if (this instanceof Fuseable) { - return onAssembly(new MonoLogFuseable<>(this, log)); - } - return onAssembly(new MonoLog<>(this, log)); - } - - /** - * Transform the item emitted by this {@link Mono} by applying a synchronous function to it. - * - *

- * - * - * @param mapper the synchronous transforming {@link Function} - * @param the transformed type - * - * @return a new {@link Mono} - */ - public final Mono map(Function mapper) { - if (this instanceof Fuseable) { - return onAssembly(new MonoMapFuseable<>(this, mapper)); - } - return onAssembly(new MonoMap<>(this, mapper)); - } - - /** - * Transform the item emitted by this {@link Mono} by applying a synchronous function to it, which is allowed - * to produce a {@code null} value. In that case, the resulting Mono completes immediately. - * This operator effectively behaves like {@link #map(Function)} followed by {@link #filter(Predicate)} - * although {@code null} is not a supported value, so it can't be filtered out. - * - *

- * - * - * @param mapper the synchronous transforming {@link Function} - * @param the transformed type - * - * @return a new {@link Mono} - */ - public final Mono mapNotNull(Function mapper) { - return this.handle((t, sink) -> { - R r = mapper.apply(t); - if (r != null) { - sink.next(r); - } - }); - } - - /** - * Transform incoming onNext, onError and onComplete signals into {@link Signal} instances, - * materializing these signals. - * Since the error is materialized as a {@code Signal}, the propagation will be stopped and onComplete will be - * emitted. Complete signal will first emit a {@code Signal.complete()} and then effectively complete the flux. - * All these {@link Signal} have a {@link Context} associated to them. - *

- * - * - * @return a {@link Mono} of materialized {@link Signal} - * @see #dematerialize() - */ - public final Mono> materialize() { - return onAssembly(new MonoMaterialize<>(this)); - } - - /** - * Merge emissions of this {@link Mono} with the provided {@link Publisher}. - * The element from the Mono may be interleaved with the elements of the Publisher. - * - *

- * - * - * @param other the {@link Publisher} to merge with - * - * @return a new {@link Flux} as the sequence is not guaranteed to be at most 1 - */ - public final Flux mergeWith(Publisher other) { - return Flux.merge(this, other); - } - - /** - * Activate metrics for this sequence, provided there is an instrumentation facade - * on the classpath (otherwise this method is a pure no-op). - *

- * Metrics are gathered on {@link Subscriber} events, and it is recommended to also - * {@link #name(String) name} (and optionally {@link #tag(String, String) tag}) the - * sequence. - *

- * The name serves as a prefix in the reported metrics names. In case no name has been provided, the default name "reactor" will be applied. - *

- * The {@link MeterRegistry} used by reactor can be configured via - * {@link reactor.util.Metrics.MicrometerConfiguration#useRegistry(MeterRegistry)} - * prior to using this operator, the default being - * {@link io.micrometer.core.instrument.Metrics#globalRegistry}. - *

- * - * @return an instrumented {@link Mono} - * - * @see #name(String) - * @see #tag(String, String) - * @deprecated Prefer using the {@link #tap(SignalListenerFactory)} with the {@link SignalListenerFactory} provided by - * the new reactor-core-micrometer module. To be removed in 3.6.0 at the earliest. - */ - @Deprecated - public final Mono metrics() { - if (!Metrics.isInstrumentationAvailable()) { - return this; - } - - if (this instanceof Fuseable) { - return onAssembly(new MonoMetricsFuseable<>(this)); - } - return onAssembly(new MonoMetrics<>(this)); - } - - /** - * Give a name to this sequence, which can be retrieved using {@link Scannable#name()} - * as long as this is the first reachable {@link Scannable#parents()}. - *

- * The name is typically visible at assembly time by the {@link #tap(SignalListenerFactory)} operator, - * which could for example be configured with a metrics listener using the name as a prefix for meters' id. - * - * @param name a name for the sequence - * - * @return the same sequence, but bearing a name - * - * @see #metrics() - * @see #tag(String, String) - */ - public final Mono name(String name) { - return MonoName.createOrAppend(this, name); - } - - /** - * Emit the first available signal from this mono or the other mono. - * - *

- * - * - * @param other the racing other {@link Mono} to compete with for the signal - * - * @return a new {@link Mono} - * @see #firstWithSignal - */ - public final Mono or(Mono other) { - if (this instanceof MonoFirstWithSignal) { - MonoFirstWithSignal a = (MonoFirstWithSignal) this; - Mono result = a.orAdditionalSource(other); - if (result != null) { - return result; - } - } - return firstWithSignal(this, other); - } - - /** - * Evaluate the emitted value against the given {@link Class} type. If the - * value matches the type, it is passed into the new {@link Mono}. Otherwise the - * value is ignored. - * - *

- * - * - * @param clazz the {@link Class} type to test values against - * - * @return a new {@link Mono} filtered on the requested type - */ - public final Mono ofType(final Class clazz) { - Objects.requireNonNull(clazz, "clazz"); - return filter(o -> clazz.isAssignableFrom(o.getClass())).cast(clazz); - } - - /** - * Simply complete the sequence by replacing an {@link Subscriber#onError(Throwable) onError signal} - * with an {@link Subscriber#onComplete() onComplete signal}. All other signals are propagated as-is. - * - *

- * - * - * @return a new {@link Mono} falling back on completion when an onError occurs - * @see #onErrorReturn(Object) - */ - public final Mono onErrorComplete() { - return onAssembly(new MonoOnErrorReturn<>(this, null, null)); - } - - /** - * Simply complete the sequence by replacing an {@link Subscriber#onError(Throwable) onError signal} - * with an {@link Subscriber#onComplete() onComplete signal} if the error matches the given - * {@link Class}. All other signals, including non-matching onError, are propagated as-is. - * - *

- * - * - * @return a new {@link Mono} falling back on completion when a matching error occurs - * @see #onErrorReturn(Class, Object) - */ - public final Mono onErrorComplete(Class type) { - Objects.requireNonNull(type, "type must not be null"); - return onErrorComplete(type::isInstance); - } - - /** - * Simply complete the sequence by replacing an {@link Subscriber#onError(Throwable) onError signal} - * with an {@link Subscriber#onComplete() onComplete signal} if the error matches the given - * {@link Predicate}. All other signals, including non-matching onError, are propagated as-is. - * - *

- * - * - * @return a new {@link Mono} falling back on completion when a matching error occurs - * @see #onErrorReturn(Predicate, Object) - */ - public final Mono onErrorComplete(Predicate predicate) { - Objects.requireNonNull(predicate, "predicate must not be null"); - return onAssembly(new MonoOnErrorReturn<>(this, predicate, null)); - } - - /** - * Let compatible operators upstream recover from errors by dropping the - * incriminating element from the sequence and continuing with subsequent elements. - * The recovered error and associated value are notified via the provided {@link BiConsumer}. - * Alternatively, throwing from that biconsumer will propagate the thrown exception downstream - * in place of the original error, which is added as a suppressed exception to the new one. - *

- * This operator is offered on {@link Mono} mainly as a way to propagate the configuration to - * upstream {@link Flux}. The mode doesn't really make sense on a {@link Mono}, since we're sure - * there will be no further value to continue with. - * {@link #onErrorResume(Function)} is a more classical fit. - *

- * Note that onErrorContinue() is a specialist operator that can make the behaviour of your - * reactive chain unclear. It operates on upstream, not downstream operators, it requires specific - * operator support to work, and the scope can easily propagate upstream into library code - * that didn't anticipate it (resulting in unintended behaviour.) - *

- * In most cases, you should instead handle the error inside the specific function which may cause - * it. Specifically, on each inner publisher you can use {@code doOnError} to log the error, and - * {@code onErrorResume(e -> Mono.empty())} to drop erroneous elements: - *

- *

-	 * .flatMap(id -> repository.retrieveById(id)
-	 *                          .doOnError(System.err::println)
-	 *                          .onErrorResume(e -> Mono.empty()))
-	 * 
- *

- * This has the advantage of being much clearer, has no ambiguity with regards to operator support, - * and cannot leak upstream. - * - * @param errorConsumer a {@link BiConsumer} fed with errors matching the {@link Class} - * and the value that triggered the error. - * @return a {@link Mono} that attempts to continue processing on errors. - */ - public final Mono onErrorContinue(BiConsumer errorConsumer) { - BiConsumer genericConsumer = errorConsumer; - return contextWrite(Context.of( - OnNextFailureStrategy.KEY_ON_NEXT_ERROR_STRATEGY, - OnNextFailureStrategy.resume(genericConsumer) - )); - } - - /** - * Let compatible operators upstream recover from errors by dropping the - * incriminating element from the sequence and continuing with subsequent elements. - * Only errors matching the specified {@code type} are recovered from. - * The recovered error and associated value are notified via the provided {@link BiConsumer}. - * Alternatively, throwing from that biconsumer will propagate the thrown exception downstream - * in place of the original error, which is added as a suppressed exception to the new one. - *

- * This operator is offered on {@link Mono} mainly as a way to propagate the configuration to - * upstream {@link Flux}. The mode doesn't really make sense on a {@link Mono}, since we're sure - * there will be no further value to continue with. - * {@link #onErrorResume(Function)} is a more classical fit. - *

- * Note that onErrorContinue() is a specialist operator that can make the behaviour of your - * reactive chain unclear. It operates on upstream, not downstream operators, it requires specific - * operator support to work, and the scope can easily propagate upstream into library code - * that didn't anticipate it (resulting in unintended behaviour.) - *

- * In most cases, you should instead handle the error inside the specific function which may cause - * it. Specifically, on each inner publisher you can use {@code doOnError} to log the error, and - * {@code onErrorResume(e -> Mono.empty())} to drop erroneous elements: - *

- *

-	 * .flatMap(id -> repository.retrieveById(id)
-	 *                          .doOnError(MyException.class, System.err::println)
-	 *                          .onErrorResume(MyException.class, e -> Mono.empty()))
-	 * 
- *

- * This has the advantage of being much clearer, has no ambiguity with regards to operator support, - * and cannot leak upstream. - * - * @param type the {@link Class} of {@link Exception} that are resumed from. - * @param errorConsumer a {@link BiConsumer} fed with errors matching the {@link Class} - * and the value that triggered the error. - * @return a {@link Mono} that attempts to continue processing on some errors. - */ - public final Mono onErrorContinue(Class type, BiConsumer errorConsumer) { - return onErrorContinue(type::isInstance, errorConsumer); - } - - /** - * Let compatible operators upstream recover from errors by dropping the - * incriminating element from the sequence and continuing with subsequent elements. - * Only errors matching the {@link Predicate} are recovered from (note that this - * predicate can be applied several times and thus must be idempotent). - * The recovered error and associated value are notified via the provided {@link BiConsumer}. - * Alternatively, throwing from that biconsumer will propagate the thrown exception downstream - * in place of the original error, which is added as a suppressed exception to the new one. - *

- * This operator is offered on {@link Mono} mainly as a way to propagate the configuration to - * upstream {@link Flux}. The mode doesn't really make sense on a {@link Mono}, since we're sure - * there will be no further value to continue with. - * {@link #onErrorResume(Function)} is a more classical fit. - *

- * Note that onErrorContinue() is a specialist operator that can make the behaviour of your - * reactive chain unclear. It operates on upstream, not downstream operators, it requires specific - * operator support to work, and the scope can easily propagate upstream into library code - * that didn't anticipate it (resulting in unintended behaviour.) - *

- * In most cases, you should instead handle the error inside the specific function which may cause - * it. Specifically, on each inner publisher you can use {@code doOnError} to log the error, and - * {@code onErrorResume(e -> Mono.empty())} to drop erroneous elements: - *

- *

-	 * .flatMap(id -> repository.retrieveById(id)
-	 *                          .doOnError(errorPredicate, System.err::println)
-	 *                          .onErrorResume(errorPredicate, e -> Mono.empty()))
-	 * 
- *

- * This has the advantage of being much clearer, has no ambiguity with regards to operator support, - * and cannot leak upstream. - * - * @param errorPredicate a {@link Predicate} used to filter which errors should be resumed from. - * This MUST be idempotent, as it can be used several times. - * @param errorConsumer a {@link BiConsumer} fed with errors matching the predicate and the value - * that triggered the error. - * @return a {@link Mono} that attempts to continue processing on some errors. - */ - public final Mono onErrorContinue(Predicate errorPredicate, - BiConsumer errorConsumer) { - //this cast is ok as only T values will be propagated in this sequence - @SuppressWarnings("unchecked") - Predicate genericPredicate = (Predicate) errorPredicate; - BiConsumer genericErrorConsumer = errorConsumer; - return contextWrite(Context.of( - OnNextFailureStrategy.KEY_ON_NEXT_ERROR_STRATEGY, - OnNextFailureStrategy.resumeIf(genericPredicate, genericErrorConsumer) - )); - } - - /** - * If an {@link #onErrorContinue(BiConsumer)} variant has been used downstream, reverts - * to the default 'STOP' mode where errors are terminal events upstream. It can be - * used for easier scoping of the on next failure strategy or to override the - * inherited strategy in a sub-stream (for example in a flatMap). It has no effect if - * {@link #onErrorContinue(BiConsumer)} has not been used downstream. - * - * @return a {@link Mono} that terminates on errors, even if {@link #onErrorContinue(BiConsumer)} - * was used downstream - */ - public final Mono onErrorStop() { - return contextWrite(Context.of( - OnNextFailureStrategy.KEY_ON_NEXT_ERROR_STRATEGY, - OnNextFailureStrategy.stop())); - } - - /** - * Transform an error emitted by this {@link Mono} by synchronously applying a function - * to it if the error matches the given predicate. Otherwise let the error pass through. - *

- * - * - * @param predicate the error predicate - * @param mapper the error transforming {@link Function} - * - * @return a {@link Mono} that transforms some source errors to other errors - */ - public final Mono onErrorMap(Predicate predicate, - Function mapper) { - return onErrorResume(predicate, e -> Mono.error(mapper.apply(e))); - } - - - /** - * Transform any error emitted by this {@link Mono} by synchronously applying a function to it. - *

- * - * - * @param mapper the error transforming {@link Function} - * - * @return a {@link Mono} that transforms source errors to other errors - */ - public final Mono onErrorMap(Function mapper) { - return onErrorResume(e -> Mono.error(mapper.apply(e))); - } - - /** - * Transform an error emitted by this {@link Mono} by synchronously applying a function - * to it if the error matches the given type. Otherwise let the error pass through. - *

- * - * - * @param type the class of the exception type to react to - * @param mapper the error transforming {@link Function} - * @param the error type - * - * @return a {@link Mono} that transforms some source errors to other errors - */ - public final Mono onErrorMap(Class type, - Function mapper) { - @SuppressWarnings("unchecked") - Function handler = (Function)mapper; - return onErrorMap(type::isInstance, handler); - } - - /** - * Subscribe to a fallback publisher when any error occurs, using a function to - * choose the fallback depending on the error. - * - *

- * - * - * @param fallback the function to choose the fallback to an alternative {@link Mono} - * - * @return a {@link Mono} falling back upon source onError - * - * @see Flux#onErrorResume - */ - public final Mono onErrorResume(Function> fallback) { - return onAssembly(new MonoOnErrorResume<>(this, fallback)); - } - - /** - * Subscribe to a fallback publisher when an error matching the given type - * occurs, using a function to choose the fallback depending on the error. - *

- * - * - * @param type the error type to match - * @param fallback the function to choose the fallback to an alternative {@link Mono} - * @param the error type - * - * @return a {@link Mono} falling back upon source onError - * @see Flux#onErrorResume - */ - public final Mono onErrorResume(Class type, - Function> fallback) { - Objects.requireNonNull(type, "type"); - @SuppressWarnings("unchecked") - Function> handler = (Function>)fallback; - return onErrorResume(type::isInstance, handler); - } - - /** - * Subscribe to a fallback publisher when an error matching a given predicate - * occurs. - *

- * - * - * @param predicate the error predicate to match - * @param fallback the function to choose the fallback to an alternative {@link Mono} - * @return a {@link Mono} falling back upon source onError - * @see Flux#onErrorResume - */ - public final Mono onErrorResume(Predicate predicate, - Function> fallback) { - Objects.requireNonNull(predicate, "predicate"); - return onErrorResume(e -> predicate.test(e) ? fallback.apply(e) : error(e)); - } - - /** - * Simply emit a captured fallback value when any error is observed on this {@link Mono}. - * - *

- * - * - * @param fallbackValue the value to emit if an error occurs - * - * @return a new falling back {@link Mono} - * @see #onErrorComplete() - */ - public final Mono onErrorReturn(final T fallbackValue) { - Objects.requireNonNull(fallbackValue, "fallbackValue must not be null"); - return onAssembly(new MonoOnErrorReturn<>(this, null, fallbackValue)); - } - - /** - * Simply emit a captured fallback value when an error of the specified type is - * observed on this {@link Mono}. - *

- * - * - * @param type the error type to match - * @param fallbackValue the value to emit if an error occurs that matches the type - * @param the error type - * - * @return a new falling back {@link Mono} - * @see #onErrorComplete(Class) - */ - public final Mono onErrorReturn(Class type, T fallbackValue) { - Objects.requireNonNull(type, "type must not be null"); - Objects.requireNonNull(fallbackValue, "fallbackValue must not be null"); - return onErrorReturn(type::isInstance, fallbackValue); - } - - /** - * Simply emit a captured fallback value when an error matching the given predicate is - * observed on this {@link Mono}. - *

- * - * - * @param predicate the error predicate to match - * @param fallbackValue the value to emit if an error occurs that matches the predicate - * - * @return a new {@link Mono} - * @see #onErrorComplete(Predicate) - */ - public final Mono onErrorReturn(Predicate predicate, T fallbackValue) { - Objects.requireNonNull(predicate, "predicate must not be null"); - Objects.requireNonNull(fallbackValue, "fallbackValue must not be null"); - return onAssembly(new MonoOnErrorReturn<>(this, predicate, fallbackValue)); - } - - /** - * Detaches both the child {@link Subscriber} and the {@link Subscription} on - * termination or cancellation. - *

This should help with odd retention scenarios when running - * with non-reactor {@link Subscriber}. - * - * @return a detachable {@link Mono} - */ - public final Mono onTerminateDetach() { - return new MonoDetach<>(this); - } - - /** - * Share a {@link Mono} for the duration of a function that may transform it and - * consume it as many times as necessary without causing multiple subscriptions - * to the upstream. - * - * @param transform the transformation function - * @param the output value type - * - * @return a new {@link Mono} - */ - public final Mono publish(Function, ? extends Mono> transform) { - return onAssembly(new MonoPublishMulticast<>(this, transform)); - } - - /** - * Run onNext, onComplete and onError on a supplied {@link Scheduler} - * {@link Worker Worker}. - *

- * This operator influences the threading context where the rest of the operators in - * the chain below it will execute, up to a new occurrence of {@code publishOn}. - *

- * - *

- * Typically used for fast publisher, slow consumer(s) scenarios. - * - *

-	 * {@code mono.publishOn(Schedulers.single()).subscribe() }
-	 * 
- * - * @param scheduler a {@link Scheduler} providing the {@link Worker} where to publish - * - * @return an asynchronously producing {@link Mono} - */ - public final Mono publishOn(Scheduler scheduler) { - if(this instanceof Callable) { - if (this instanceof Fuseable.ScalarCallable) { - try { - T value = block(); - return onAssembly(new MonoSubscribeOnValue<>(value, scheduler)); - } - catch (Throwable t) { - //leave MonoSubscribeOnCallable defer error - } - } - @SuppressWarnings("unchecked") - Callable c = (Callable)this; - return onAssembly(new MonoSubscribeOnCallable<>(c, scheduler)); - } - return onAssembly(new MonoPublishOn<>(this, scheduler)); - } - - /** - * Repeatedly and indefinitely subscribe to the source upon completion of the - * previous subscription. - * - *

- * - * - * @return an indefinitely repeated {@link Flux} on onComplete - */ - public final Flux repeat() { - return repeat(Flux.ALWAYS_BOOLEAN_SUPPLIER); - } - - /** - * Repeatedly subscribe to the source if the predicate returns true after completion of the previous subscription. - * - *

- * - * - * @param predicate the boolean to evaluate on onComplete. - * - * @return a {@link Flux} that repeats on onComplete while the predicate matches - * - */ - public final Flux repeat(BooleanSupplier predicate) { - return Flux.onAssembly(new MonoRepeatPredicate<>(this, predicate)); - } - - /** - * Repeatedly subscribe to the source {@literal numRepeat} times. This results in - * {@code numRepeat + 1} total subscriptions to the original source. As a consequence, - * using 0 plays the original sequence once. - * - *

- * - * - * @param numRepeat the number of times to re-subscribe on onComplete (positive, or 0 for original sequence only) - * @return a {@link Flux} that repeats on onComplete, up to the specified number of repetitions - */ - public final Flux repeat(long numRepeat) { - if (numRepeat == 0) { - return this.flux(); - } - return Flux.onAssembly(new MonoRepeat<>(this, numRepeat)); - } - - /** - * Repeatedly subscribe to the source if the predicate returns true after completion of the previous - * subscription. A specified maximum of repeat will limit the number of re-subscribe. - * - *

- * - * - * @param numRepeat the number of times to re-subscribe on complete (positive, or 0 for original sequence only) - * @param predicate the boolean to evaluate on onComplete - * - * @return a {@link Flux} that repeats on onComplete while the predicate matches, - * up to the specified number of repetitions - */ - public final Flux repeat(long numRepeat, BooleanSupplier predicate) { - if (numRepeat < 0L) { - throw new IllegalArgumentException("numRepeat >= 0 required"); - } - if (numRepeat == 0) { - return this.flux(); - } - return Flux.defer(() -> repeat(Flux.countingBooleanSupplier(predicate, numRepeat))); - } - - /** - * Repeatedly subscribe to this {@link Mono} when a companion sequence emits elements in - * response to the flux completion signal. Any terminal signal from the companion - * sequence will terminate the resulting {@link Flux} with the same signal immediately. - *

If the companion sequence signals when this {@link Mono} is active, the repeat - * attempt is suppressed. - * - *

- * - *

- * Note that if the companion {@link Publisher} created by the {@code repeatFactory} - * emits {@link Context} as trigger objects, the content of these Context will be added - * to the operator's own {@link Context}. - * - * @param repeatFactory the {@link Function} that returns the associated {@link Publisher} - * companion, given a {@link Flux} that signals each onComplete as a {@link Long} - * representing the number of source elements emitted in the latest attempt (0 or 1). - * - * @return a {@link Flux} that repeats on onComplete when the companion {@link Publisher} produces an - * onNext signal - */ - public final Flux repeatWhen(Function, ? extends Publisher> repeatFactory) { - return Flux.onAssembly(new MonoRepeatWhen<>(this, repeatFactory)); - } - - /** - * Repeatedly subscribe to this {@link Mono} as long as the current subscription to this - * {@link Mono} completes empty and the companion {@link Publisher} produces an onNext signal. - *

- * Any terminal signal will terminate the resulting {@link Mono} with the same signal immediately. - * - *

- * - * - * @param repeatFactory the {@link Function} that returns the associated {@link Publisher} - * companion, given a {@link Flux} that signals each onComplete as a 0-based incrementing {@link Long}. - * - * @return a {@link Mono} that resubscribes to this {@link Mono} if the previous subscription was empty, - * as long as the companion {@link Publisher} produces an onNext signal - * - */ - public final Mono repeatWhenEmpty(Function, ? extends Publisher> repeatFactory) { - return repeatWhenEmpty(Integer.MAX_VALUE, repeatFactory); - } - - /** - * Repeatedly subscribe to this {@link Mono} as long as the current subscription to this - * {@link Mono} completes empty and the companion {@link Publisher} produces an onNext signal. - *

- * Any terminal signal will terminate the resulting {@link Mono} with the same signal immediately. - *

- * Emits an {@link IllegalStateException} if {@code maxRepeat} is exceeded (provided - * it is different from {@code Integer.MAX_VALUE}). - * - *

- * - * - * @param maxRepeat the maximum number of repeats (infinite if {@code Integer.MAX_VALUE}) - * @param repeatFactory the {@link Function} that returns the associated {@link Publisher} - * companion, given a {@link Flux} that signals each onComplete as a 0-based incrementing {@link Long}. - * - * @return a {@link Mono} that resubscribes to this {@link Mono} if the previous subscription was empty, - * as long as the companion {@link Publisher} produces an onNext signal and the maximum number of repeats isn't exceeded. - */ - public final Mono repeatWhenEmpty(int maxRepeat, Function, ? extends Publisher> repeatFactory) { - return Mono.defer(() -> this.repeatWhen(o -> { - if (maxRepeat == Integer.MAX_VALUE) { - return repeatFactory.apply(o.index().map(Tuple2::getT1)); - } - else { - return repeatFactory.apply(o - .index() - .map(Tuple2::getT1) - .take(maxRepeat, false) - .concatWith(Flux.error(() -> new IllegalStateException("Exceeded maximum number of repeats")))); - } - }).next()); - } - - - /** - * Re-subscribes to this {@link Mono} sequence if it signals any error, indefinitely. - *

- * - * - * @return a {@link Mono} that retries on onError - */ - public final Mono retry() { - return retry(Long.MAX_VALUE); - } - - /** - * Re-subscribes to this {@link Mono} sequence if it signals any error, for a fixed - * number of times. - *

- * Note that passing {@literal Long.MAX_VALUE} is treated as infinite retry. - *

- * - * - * @param numRetries the number of times to tolerate an error - * - * @return a {@link Mono} that retries on onError up to the specified number of retry attempts. - */ - public final Mono retry(long numRetries) { - return onAssembly(new MonoRetry<>(this, numRetries)); - } - - /** - * Retries this {@link Mono} in response to signals emitted by a companion {@link Publisher}. - * The companion is generated by the provided {@link Retry} instance, see {@link Retry#max(long)}, {@link Retry#maxInARow(long)} - * and {@link Retry#backoff(long, Duration)} for readily available strategy builders. - *

- * The operator generates a base for the companion, a {@link Flux} of {@link reactor.util.retry.Retry.RetrySignal} - * which each give metadata about each retryable failure whenever this {@link Mono} signals an error. The final companion - * should be derived from that base companion and emit data in response to incoming onNext (although it can emit less - * elements, or delay the emissions). - *

- * Terminal signals in the companion terminate the sequence with the same signal, so emitting an {@link Subscriber#onError(Throwable)} - * will fail the resulting {@link Mono} with that same error. - *

- * - *

- * Note that the {@link reactor.util.retry.Retry.RetrySignal} state can be transient and change between each source - * {@link org.reactivestreams.Subscriber#onError(Throwable) onError} or - * {@link org.reactivestreams.Subscriber#onNext(Object) onNext}. If processed with a delay, - * this could lead to the represented state being out of sync with the state at which the retry - * was evaluated. Map it to {@link reactor.util.retry.Retry.RetrySignal#copy()} right away to mediate this. - *

- * Note that if the companion {@link Publisher} created by the {@code whenFactory} - * emits {@link Context} as trigger objects, these {@link Context} will be merged with - * the previous Context: - *

- *
-	 * {@code
-	 * Retry customStrategy = Retry.from(companion -> companion.handle((retrySignal, sink) -> {
-	 * 	    Context ctx = sink.currentContext();
-	 * 	    int rl = ctx.getOrDefault("retriesLeft", 0);
-	 * 	    if (rl > 0) {
-	 *		    sink.next(Context.of(
-	 *		        "retriesLeft", rl - 1,
-	 *		        "lastError", retrySignal.failure()
-	 *		    ));
-	 * 	    } else {
-	 * 	        sink.error(Exceptions.retryExhausted("retries exhausted", retrySignal.failure()));
-	 * 	    }
-	 * }));
-	 * Mono retried = originalMono.retryWhen(customStrategy);
-	 * }
- *
- * - * @param retrySpec the {@link Retry} strategy that will generate the companion {@link Publisher}, - * given a {@link Flux} that signals each onError as a {@link reactor.util.retry.Retry.RetrySignal}. - * - * @return a {@link Mono} that retries on onError when a companion {@link Publisher} produces an onNext signal - * @see Retry#max(long) - * @see Retry#maxInARow(long) - * @see Retry#backoff(long, Duration) - */ - public final Mono retryWhen(Retry retrySpec) { - return onAssembly(new MonoRetryWhen<>(this, retrySpec)); - } - - /** - * Prepare a {@link Mono} which shares this {@link Mono} result similar to {@link Flux#shareNext()}. - * This will effectively turn this {@link Mono} into a hot task when the first - * {@link Subscriber} subscribes using {@link #subscribe()} API. Further {@link Subscriber} will share the same {@link Subscription} - * and therefore the same result. - * It's worth noting this is an un-cancellable {@link Subscription}. - *

- * - * - * @return a new {@link Mono} - */ - public final Mono share() { - if (this instanceof Fuseable.ScalarCallable) { - return this; - } - - if (this instanceof NextProcessor && ((NextProcessor) this).isRefCounted) { //TODO should we check whether the NextProcessor has a source or not? - return this; - } - return new NextProcessor<>(this, true); - } - - /** - * Expect exactly one item from this {@link Mono} source or signal - * {@link java.util.NoSuchElementException} for an empty source. - *

- * - *

- * Note Mono doesn't need {@link Flux#single(Object)}, since it is equivalent to - * {@link #defaultIfEmpty(Object)} in a {@link Mono}. - * - * @return a {@link Mono} with the single item or an error signal - */ - public final Mono single() { - if (this instanceof Callable) { - if (this instanceof Fuseable.ScalarCallable) { - @SuppressWarnings("unchecked") - Fuseable.ScalarCallable scalarCallable = (Fuseable.ScalarCallable) this; - - T v; - try { - v = scalarCallable.call(); - } - catch (Exception e) { - return Mono.error(Exceptions.unwrap(e)); - } - if (v == null) { - return Mono.error(new NoSuchElementException("Source was a (constant) empty")); - } - return Mono.just(v); - } - @SuppressWarnings("unchecked") - Callable thiz = (Callable)this; - return Mono.onAssembly(new MonoSingleCallable<>(thiz)); - } - return Mono.onAssembly(new MonoSingleMono<>(this)); - } - - /** - * Wrap the item produced by this {@link Mono} source into an Optional - * or emit an empty Optional for an empty source. - *

- * - *

- * - * @return a {@link Mono} with an Optional containing the item, an empty optional or an error signal - */ - public final Mono> singleOptional() { - if (this instanceof Callable) { - if (this instanceof Fuseable.ScalarCallable) { - @SuppressWarnings("unchecked") - Fuseable.ScalarCallable scalarCallable = (Fuseable.ScalarCallable) this; - - T v; - try { - v = scalarCallable.call(); - } - catch (Exception e) { - return Mono.error(Exceptions.unwrap(e)); - } - return Mono.just(Optional.ofNullable(v)); - } - @SuppressWarnings("unchecked") - Callable thiz = (Callable)this; - return Mono.onAssembly(new MonoSingleOptionalCallable<>(thiz)); - } - return Mono.onAssembly(new MonoSingleOptional<>(this)); - } - - /** - * Subscribe to this {@link Mono} and request unbounded demand. - *

- * This version doesn't specify any consumption behavior for the events from the - * chain, especially no error handling, so other variants should usually be preferred. - * - *

- * - * - * @return a new {@link Disposable} that can be used to cancel the underlying {@link Subscription} - */ - public final Disposable subscribe() { - if(this instanceof NextProcessor){ - NextProcessor s = (NextProcessor)this; - // Mono#share() should return a new lambda subscriber during subscribe. - // This can now be precisely detected with source != null in combination to the isRefCounted boolean being true. - // `Sinks.one().subscribe()` case is now split into a separate implementation. - // Otherwise, this is a (legacy) #toProcessor() usage, and we return the processor itself below (and don't forget to connect() it): - if (s.source != null && !s.isRefCounted) { - s.subscribe(new LambdaMonoSubscriber<>(null, null, null, null, null)); - s.connect(); - return s; - } - } - return subscribeWith(new LambdaMonoSubscriber<>(null, null, null, null, null)); - } - - /** - * Subscribe a {@link Consumer} to this {@link Mono} that will consume all the - * sequence. It will request an unbounded demand ({@code Long.MAX_VALUE}). - *

- * For a passive version that observe and forward incoming data see {@link #doOnNext(java.util.function.Consumer)}. - *

- * Keep in mind that since the sequence can be asynchronous, this will immediately - * return control to the calling thread. This can give the impression the consumer is - * not invoked when executing in a main thread or a unit test for instance. - * - *

- * - * - * @param consumer the consumer to invoke on each value (onNext signal) - * - * @return a new {@link Disposable} that can be used to cancel the underlying {@link Subscription} - */ - public final Disposable subscribe(Consumer consumer) { - Objects.requireNonNull(consumer, "consumer"); - return subscribe(consumer, null, null); - } - - /** - * Subscribe to this {@link Mono} with a {@link Consumer} that will consume all the - * elements in the sequence, as well as a {@link Consumer} that will handle errors. - * The subscription will request an unbounded demand ({@code Long.MAX_VALUE}). - *

- * For a passive version that observe and forward incoming data see {@link #doOnSuccess(Consumer)} and - * {@link #doOnError(java.util.function.Consumer)}. - *

- * Keep in mind that since the sequence can be asynchronous, this will immediately - * return control to the calling thread. This can give the impression the consumer is - * not invoked when executing in a main thread or a unit test for instance. - * - *

- * - * - * @param consumer the consumer to invoke on each next signal - * @param errorConsumer the consumer to invoke on error signal - * - * @return a new {@link Disposable} that can be used to cancel the underlying {@link Subscription} - */ - public final Disposable subscribe(@Nullable Consumer consumer, Consumer errorConsumer) { - Objects.requireNonNull(errorConsumer, "errorConsumer"); - return subscribe(consumer, errorConsumer, null); - } - - /** - * Subscribe {@link Consumer} to this {@link Mono} that will respectively consume all the - * elements in the sequence, handle errors and react to completion. The subscription - * will request unbounded demand ({@code Long.MAX_VALUE}). - *

- * For a passive version that observe and forward incoming data see {@link #doOnSuccess(Consumer)} and - * {@link #doOnError(java.util.function.Consumer)}. - *

- * Keep in mind that since the sequence can be asynchronous, this will immediately - * return control to the calling thread. This can give the impression the consumer is - * not invoked when executing in a main thread or a unit test for instance. - * - *

- * - * - * @param consumer the consumer to invoke on each value - * @param errorConsumer the consumer to invoke on error signal - * @param completeConsumer the consumer to invoke on complete signal - * - * @return a new {@link Disposable} that can be used to cancel the underlying {@link Subscription} - */ - public final Disposable subscribe( - @Nullable Consumer consumer, - @Nullable Consumer errorConsumer, - @Nullable Runnable completeConsumer) { - return subscribe(consumer, errorConsumer, completeConsumer, (Context) null); - } - - /** - * Subscribe {@link Consumer} to this {@link Mono} that will respectively consume all the - * elements in the sequence, handle errors, react to completion, and request upon subscription. - * It will let the provided {@link Subscription subscriptionConsumer} - * request the adequate amount of data, or request unbounded demand - * {@code Long.MAX_VALUE} if no such consumer is provided. - *

- * For a passive version that observe and forward incoming data see {@link #doOnSuccess(Consumer)} and - * {@link #doOnError(java.util.function.Consumer)}. - *

- * Keep in mind that since the sequence can be asynchronous, this will immediately - * return control to the calling thread. This can give the impression the consumer is - * not invoked when executing in a main thread or a unit test for instance. - * - *

- * - * - * @param consumer the consumer to invoke on each value - * @param errorConsumer the consumer to invoke on error signal - * @param completeConsumer the consumer to invoke on complete signal - * @param subscriptionConsumer the consumer to invoke on subscribe signal, to be used - * for the initial {@link Subscription#request(long) request}, or null for max request - * - * @return a new {@link Disposable} that can be used to cancel the underlying {@link Subscription} - */ //TODO maybe deprecate in 3.4, provided there is at least an alternative for tests - public final Disposable subscribe( - @Nullable Consumer consumer, - @Nullable Consumer errorConsumer, - @Nullable Runnable completeConsumer, - @Nullable Consumer subscriptionConsumer) { - return subscribeWith(new LambdaMonoSubscriber<>(consumer, errorConsumer, - completeConsumer, subscriptionConsumer, null)); - } - - /** - * Subscribe {@link Consumer} to this {@link Mono} that will respectively consume all the - * elements in the sequence, handle errors and react to completion. Additionally, a {@link Context} - * is tied to the subscription. At subscription, an unbounded request is implicitly made. - *

- * For a passive version that observe and forward incoming data see {@link #doOnSuccess(Consumer)} and - * {@link #doOnError(java.util.function.Consumer)}. - *

- * Keep in mind that since the sequence can be asynchronous, this will immediately - * return control to the calling thread. This can give the impression the consumer is - * not invoked when executing in a main thread or a unit test for instance. - * - *

- * - * - * @param consumer the consumer to invoke on each value - * @param errorConsumer the consumer to invoke on error signal - * @param completeConsumer the consumer to invoke on complete signal - * @param initialContext the {@link Context} for the subscription - * - * @return a new {@link Disposable} that can be used to cancel the underlying {@link Subscription} - */ - public final Disposable subscribe( - @Nullable Consumer consumer, - @Nullable Consumer errorConsumer, - @Nullable Runnable completeConsumer, - @Nullable Context initialContext) { - return subscribeWith(new LambdaMonoSubscriber<>(consumer, errorConsumer, - completeConsumer, null, initialContext)); - } - - @Override - @SuppressWarnings("unchecked") - public final void subscribe(Subscriber actual) { - CorePublisher publisher = Operators.onLastAssembly(this); - CoreSubscriber subscriber = Operators.toCoreSubscriber(actual); - - if (subscriber instanceof Fuseable.QueueSubscription && this != publisher && this instanceof Fuseable && !(publisher instanceof Fuseable)) { - subscriber = new FluxHide.SuppressFuseableSubscriber<>(subscriber); - } - - try { - if (publisher instanceof OptimizableOperator) { - OptimizableOperator operator = (OptimizableOperator) publisher; - while (true) { - subscriber = operator.subscribeOrReturn(subscriber); - if (subscriber == null) { - // null means "I will subscribe myself", returning... - return; - } - - OptimizableOperator newSource = operator.nextOptimizableSource(); - if (newSource == null) { - publisher = operator.source(); - break; - } - operator = newSource; - } - } - - publisher.subscribe(subscriber); - } - catch (Throwable e) { - Operators.reportThrowInSubscribe(subscriber, e); - return; - } - } - - /** - * An internal {@link Publisher#subscribe(Subscriber)} that will bypass - * {@link Hooks#onLastOperator(Function)} pointcut. - *

- * In addition to behave as expected by {@link Publisher#subscribe(Subscriber)} - * in a controlled manner, it supports direct subscribe-time {@link Context} passing. - * - * @param actual the {@link Subscriber} interested into the published sequence - * @see Publisher#subscribe(Subscriber) - */ - public abstract void subscribe(CoreSubscriber actual); - - /** - * Run subscribe, onSubscribe and request on a specified {@link Scheduler}'s {@link Worker}. - * As such, placing this operator anywhere in the chain will also impact the execution - * context of onNext/onError/onComplete signals from the beginning of the chain up to - * the next occurrence of a {@link #publishOn(Scheduler) publishOn}. - *

- * - * - *

-	 * {@code mono.subscribeOn(Schedulers.parallel()).subscribe()) }
-	 * 
- * - * @param scheduler a {@link Scheduler} providing the {@link Worker} where to subscribe - * - * @return a {@link Mono} requesting asynchronously - * @see #publishOn(Scheduler) - */ - public final Mono subscribeOn(Scheduler scheduler) { - if(this instanceof Callable) { - if (this instanceof Fuseable.ScalarCallable) { - try { - T value = block(); - return onAssembly(new MonoSubscribeOnValue<>(value, scheduler)); - } - catch (Throwable t) { - //leave MonoSubscribeOnCallable defer error - } - } - @SuppressWarnings("unchecked") - Callable c = (Callable)this; - return onAssembly(new MonoSubscribeOnCallable<>(c, - scheduler)); - } - return onAssembly(new MonoSubscribeOn<>(this, scheduler)); - } - - /** - * Subscribe the given {@link Subscriber} to this {@link Mono} and return said - * {@link Subscriber}, allowing subclasses with a richer API to be used fluently. - * - * @param subscriber the {@link Subscriber} to subscribe with - * @param the reified type of the {@link Subscriber} for chaining - * - * @return the passed {@link Subscriber} after subscribing it to this {@link Mono} - */ - public final > E subscribeWith(E subscriber) { - subscribe(subscriber); - return subscriber; - } - - /** - * Fallback to an alternative {@link Mono} if this mono is completed without data - * - *

- * - * - * @param alternate the alternate mono if this mono is empty - * - * @return a {@link Mono} falling back upon source completing without elements - * @see Flux#switchIfEmpty - */ - public final Mono switchIfEmpty(Mono alternate) { - return onAssembly(new MonoSwitchIfEmpty<>(this, alternate)); - } - - /** - * Tag this mono with a key/value pair. These can be retrieved as a {@link Set} of - * all tags throughout the publisher chain by using {@link Scannable#tags()} (as - * traversed by {@link Scannable#parents()}). - *

- * The name is typically visible at assembly time by the {@link #tap(SignalListenerFactory)} operator, - * which could for example be configured with a metrics listener applying the tag(s) to its meters. - * - * @param key a tag key - * @param value a tag value - * - * @return the same sequence, but bearing tags - * - * @see #name(String) - * @see #metrics() - */ - public final Mono tag(String key, String value) { - return MonoName.createOrAppend(this, key, value); - } - - /** - * Give this Mono a chance to resolve within a specified time frame but complete if it - * doesn't. This works a bit like {@link #timeout(Duration)} except that the resulting - * {@link Mono} completes rather than errors when the timer expires. - *

- * - *

- * The timeframe is evaluated using the {@link Schedulers#parallel() parallel Scheduler}. - * - * @param duration the maximum duration to wait for the source Mono to resolve. - * @return a new {@link Mono} that will propagate the signals from the source unless - * no signal is received for {@code duration}, in which case it completes. - */ - public final Mono take(Duration duration) { - return take(duration, Schedulers.parallel()); - } - - /** - * Give this Mono a chance to resolve within a specified time frame but complete if it - * doesn't. This works a bit like {@link #timeout(Duration)} except that the resulting - * {@link Mono} completes rather than errors when the timer expires. - *

- * - *

- * The timeframe is evaluated using the provided {@link Scheduler}. - * - * @param duration the maximum duration to wait for the source Mono to resolve. - * @param timer the {@link Scheduler} on which to measure the duration. - * - * @return a new {@link Mono} that will propagate the signals from the source unless - * no signal is received for {@code duration}, in which case it completes. - */ - public final Mono take(Duration duration, Scheduler timer) { - return takeUntilOther(Mono.delay(duration, timer)); - } - - /** - * Give this Mono a chance to resolve before a companion {@link Publisher} emits. If - * the companion emits before any signal from the source, the resulting Mono will - * complete. Otherwise, it will relay signals from the source. - *

- * - * - * @param other a companion {@link Publisher} that shortcircuits the source with an - * onComplete signal if it emits before the source emits. - * - * @return a new {@link Mono} that will propagate the signals from the source unless - * a signal is first received from the companion {@link Publisher}, in which case it - * completes. - */ - public final Mono takeUntilOther(Publisher other) { - return onAssembly(new MonoTakeUntilOther<>(this, other)); - } - - /** - * Tap into Reactive Streams signals emitted or received by this {@link Mono} and notify a stateful per-{@link Subscriber} - * {@link SignalListener}. - *

- * Any exception thrown by the {@link SignalListener} methods causes the subscription to be cancelled - * and the subscriber to be terminated with an {@link Subscriber#onError(Throwable) onError signal} of that - * exception. Note that {@link SignalListener#doFinally(SignalType)}, {@link SignalListener#doAfterComplete()} and - * {@link SignalListener#doAfterError(Throwable)} instead just {@link Operators#onErrorDropped(Throwable, Context) drop} - * the exception. - *

- * This simplified variant assumes the state is purely initialized within the {@link Supplier}, - * as it is called for each incoming {@link Subscriber} without additional context. - *

- * When the context-propagation library - * is available at runtime and the downstream {@link ContextView} is not empty, this operator implicitly uses the library - * to restore thread locals around all invocations of {@link SignalListener} methods. Typically, this would be done - * in conjunction with the use of {@link #contextCapture()} operator down the chain. - * - * @param simpleListenerGenerator the {@link Supplier} to create a new {@link SignalListener} on each subscription - * @return a new {@link Mono} with side effects defined by generated {@link SignalListener} - * @see #tap(Function) - * @see #tap(SignalListenerFactory) - */ - public final Mono tap(Supplier> simpleListenerGenerator) { - return tap(new SignalListenerFactory() { - @Override - public Void initializePublisherState(Publisher ignored) { - return null; - } - - @Override - public SignalListener createListener(Publisher ignored1, ContextView ignored2, Void ignored3) { - return simpleListenerGenerator.get(); - } - }); - } - - /** - * Tap into Reactive Streams signals emitted or received by this {@link Mono} and notify a stateful per-{@link Subscriber} - * {@link SignalListener}. - *

- * Any exception thrown by the {@link SignalListener} methods causes the subscription to be cancelled - * and the subscriber to be terminated with an {@link Subscriber#onError(Throwable) onError signal} of that - * exception. Note that {@link SignalListener#doFinally(SignalType)}, {@link SignalListener#doAfterComplete()} and - * {@link SignalListener#doAfterError(Throwable)} instead just {@link Operators#onErrorDropped(Throwable, Context) drop} - * the exception. - *

- * This simplified variant allows the {@link SignalListener} to be constructed for each subscription - * with access to the incoming {@link Subscriber}'s {@link ContextView}. - *

- * When the context-propagation library - * is available at runtime and the {@link ContextView} is not empty, this operator implicitly uses the library - * to restore thread locals around all invocations of {@link SignalListener} methods. Typically, this would be done - * in conjunction with the use of {@link #contextCapture()} operator down the chain. - * - * @param listenerGenerator the {@link Function} to create a new {@link SignalListener} on each subscription - * @return a new {@link Mono} with side effects defined by generated {@link SignalListener} - * @see #tap(Supplier) - * @see #tap(SignalListenerFactory) - */ - public final Mono tap(Function> listenerGenerator) { - return tap(new SignalListenerFactory() { - @Override - public Void initializePublisherState(Publisher ignored) { - return null; - } - - @Override - public SignalListener createListener(Publisher ignored1, ContextView listenerContext, Void ignored2) { - return listenerGenerator.apply(listenerContext); - } - }); - } - - /** - * Tap into Reactive Streams signals emitted or received by this {@link Mono} and notify a stateful per-{@link Subscriber} - * {@link SignalListener} created by the provided {@link SignalListenerFactory}. - *

- * The factory will initialize a {@link SignalListenerFactory#initializePublisherState(Publisher) state object} for - * each {@link Flux} or {@link Mono} instance it is used with, and that state will be cached and exposed for each - * incoming {@link Subscriber} in order to generate the associated {@link SignalListenerFactory#createListener(Publisher, ContextView, Object) listener}. - *

- * Any exception thrown by the {@link SignalListener} methods causes the subscription to be cancelled - * and the subscriber to be terminated with an {@link Subscriber#onError(Throwable) onError signal} of that - * exception. Note that {@link SignalListener#doFinally(SignalType)}, {@link SignalListener#doAfterComplete()} and - * {@link SignalListener#doAfterError(Throwable)} instead just {@link Operators#onErrorDropped(Throwable, Context) drop} - * the exception. - *

- * When the context-propagation library - * is available at runtime and the downstream {@link ContextView} is not empty, this operator implicitly uses the library - * to restore thread locals around all invocations of {@link SignalListener} methods. Typically, this would be done - * in conjunction with the use of {@link #contextCapture()} operator down the chain. - * - * @param listenerFactory the {@link SignalListenerFactory} to create a new {@link SignalListener} on each subscription - * @return a new {@link Flux} with side effects defined by generated {@link SignalListener} - * @see #tap(Supplier) - * @see #tap(Function) - */ - public final Mono tap(SignalListenerFactory listenerFactory) { - if (this instanceof Fuseable) { - return onAssembly(new MonoTapFuseable<>(this, listenerFactory)); - } - return onAssembly(new MonoTap<>(this, listenerFactory)); - } - - /** - * Return a {@code Mono} which only replays complete and error signals - * from this {@link Mono}. - * - *

- * - * - *

Discard Support: This operator discards the element from the source. - * - * @return a {@link Mono} ignoring its payload (actively dropping) - */ - public final Mono then() { - return empty(this); - } - - /** - * Let this {@link Mono} complete then play another Mono. - *

- * In other words ignore element from this {@link Mono} and transform its completion signal into the - * emission and completion signal of a provided {@code Mono}. Error signal is - * replayed in the resulting {@code Mono}. - * - *

- * - * - *

Discard Support: This operator discards the element from the source. - * - * @param other a {@link Mono} to emit from after termination - * @param the element type of the supplied Mono - * - * @return a new {@link Mono} that emits from the supplied {@link Mono} - */ - public final Mono then(Mono other) { - if (this instanceof MonoIgnoreThen) { - MonoIgnoreThen a = (MonoIgnoreThen) this; - return a.shift(other); - } - return onAssembly(new MonoIgnoreThen<>(new Publisher[] { this }, other)); - } - - /** - * Let this {@link Mono} complete successfully, then emit the provided value. On an error in the original {@link Mono}, the error signal is propagated instead. - *

- * - * - *

Discard Support: This operator discards the element from the source. - * - * @param value a value to emit after successful termination - * @param the element type of the supplied value - * - * @return a new {@link Mono} that emits the supplied value - */ - public final Mono thenReturn(V value) { - return then(Mono.just(value)); - } - - /** - * Return a {@code Mono} that waits for this {@link Mono} to complete then - * for a supplied {@link Publisher Publisher<Void>} to also complete. The - * second completion signal is replayed, or any error signal that occurs instead. - *

- * - * - *

Discard Support: This operator discards the element from the source. - * - * @param other a {@link Publisher} to wait for after this Mono's termination - * @return a new {@link Mono} completing when both publishers have completed in - * sequence - */ - public final Mono thenEmpty(Publisher other) { - return then(fromDirect(other)); - } - - /** - * Let this {@link Mono} complete successfully then play another {@link Publisher}. On an error in the original {@link Mono}, the error signal is propagated instead. - *

- * In other words ignore the element from this mono and transform the completion signal into a - * {@code Flux} that will emit elements from the provided {@link Publisher}. - * - *

- * - * - *

Discard Support: This operator discards the element from the source. - * - * @param other a {@link Publisher} to emit from after termination - * @param the element type of the supplied Publisher - * - * @return a new {@link Flux} that emits from the supplied {@link Publisher} after - * this Mono completes. - */ - public final Flux thenMany(Publisher other) { - @SuppressWarnings("unchecked") - Flux concat = (Flux)Flux.concat(ignoreElement(), other); - return Flux.onAssembly(concat); - } - - - /** - * Times this {@link Mono} {@link Subscriber#onNext(Object)} event, encapsulated into a {@link Timed} object - * that lets downstream consumer look at various time information gathered with nanosecond - * resolution using the default clock ({@link Schedulers#parallel()}): - *

    - *
  • {@link Timed#elapsed()}: the time in nanoseconds since subscription, as a {@link Duration}. - * This is functionally equivalent to {@link #elapsed()}, with a more expressive and precise - * representation than a {@link Tuple2} with a long.
  • - *
  • {@link Timed#timestamp()}: the timestamp of this onNext, as an {@link java.time.Instant} - * (with nanoseconds part). This is functionally equivalent to {@link #timestamp()}, with a more - * expressive and precise representation than a {@link Tuple2} with a long.
  • - *
  • {@link Timed#elapsedSinceSubscription()}: for {@link Mono} this is the same as - * {@link Timed#elapsed()}.
  • - *
- *

- * The {@link Timed} object instances are safe to store and use later, as they are created as an - * immutable wrapper around the {@code } value and immediately passed downstream. - *

- * - * - * @return a timed {@link Mono} - * @see #elapsed() - * @see #timestamp() - */ - public final Mono> timed() { - return this.timed(Schedulers.parallel()); - } - - /** - * Times this {@link Mono} {@link Subscriber#onNext(Object)} event, encapsulated into a {@link Timed} object - * that lets downstream consumer look at various time information gathered with nanosecond - * resolution using the provided {@link Scheduler} as a clock: - *

    - *
  • {@link Timed#elapsed()}: the time in nanoseconds since subscription, as a {@link Duration}. - * This is functionally equivalent to {@link #elapsed()}, with a more expressive and precise - * representation than a {@link Tuple2} with a long.
  • - *
  • {@link Timed#timestamp()}: the timestamp of this onNext, as an {@link java.time.Instant} - * (with nanoseconds part). This is functionally equivalent to {@link #timestamp()}, with a more - * expressive and precise representation than a {@link Tuple2} with a long.
  • - *
  • {@link Timed#elapsedSinceSubscription()}: for {@link Mono} this is the same as - * {@link Timed#elapsed()}.
  • - *
- *

- * The {@link Timed} object instances are safe to store and use later, as they are created as an - * immutable wrapper around the {@code } value and immediately passed downstream. - *

- * - * - * @return a timed {@link Mono} - * @see #elapsed(Scheduler) - * @see #timestamp(Scheduler) - */ - public final Mono> timed(Scheduler clock) { - return onAssembly(new MonoTimed<>(this, clock)); - } - - /** - * Propagate a {@link TimeoutException} in case no item arrives within the given - * {@link Duration}. - * - *

- * - * - * @param timeout the timeout before the onNext signal from this {@link Mono} - * - * @return a {@link Mono} that can time out - */ - public final Mono timeout(Duration timeout) { - return timeout(timeout, Schedulers.parallel()); - } - - /** - * Switch to a fallback {@link Mono} in case no item arrives within the given {@link Duration}. - * - *

- * If the fallback {@link Mono} is null, signal a {@link TimeoutException} instead. - * - *

- * - * - * @param timeout the timeout before the onNext signal from this {@link Mono} - * @param fallback the fallback {@link Mono} to subscribe to when a timeout occurs - * - * @return a {@link Mono} that will fallback to a different {@link Mono} in case of timeout - */ - public final Mono timeout(Duration timeout, Mono fallback) { - return timeout(timeout, fallback, Schedulers.parallel()); - } - - /** - * Signal a {@link TimeoutException} error in case an item doesn't arrive before the given period, - * as measured on the provided {@link Scheduler}. - * - *

- * - * - * @param timeout the timeout before the onNext signal from this {@link Mono} - * @param timer a time-capable {@link Scheduler} instance to run the delay on - * - * @return an expirable {@link Mono} - */ - public final Mono timeout(Duration timeout, Scheduler timer) { - return timeout(timeout, null, timer); - } - - /** - * Switch to a fallback {@link Mono} in case an item doesn't arrive before the given period, - * as measured on the provided {@link Scheduler}. - * - *

If the given {@link Mono} is null, signal a {@link TimeoutException}. - * - *

- * - * - * @param timeout the timeout before the onNext signal from this {@link Mono} - * @param fallback the fallback {@link Mono} to subscribe when a timeout occurs - * @param timer a time-capable {@link Scheduler} instance to run on - * - * @return an expirable {@link Mono} with a fallback {@link Mono} - */ - public final Mono timeout(Duration timeout, @Nullable Mono fallback, - Scheduler timer) { - final Mono _timer = Mono.delay(timeout, timer).onErrorReturn(0L); - - if(fallback == null) { - return onAssembly(new MonoTimeout<>(this, _timer, timeout.toMillis() + "ms")); - } - return onAssembly(new MonoTimeout<>(this, _timer, fallback)); - } - - /** - * Signal a {@link TimeoutException} in case the item from this {@link Mono} has - * not been emitted before the given {@link Publisher} emits. - * - *

- * - * - * @param firstTimeout the timeout {@link Publisher} that must not emit before the first signal from this {@link Mono} - * @param the element type of the timeout Publisher - * - * @return an expirable {@link Mono} if the item does not come before a {@link Publisher} signals - * - */ - public final Mono timeout(Publisher firstTimeout) { - return onAssembly(new MonoTimeout<>(this, firstTimeout, "first signal from a Publisher")); - } - - /** - * Switch to a fallback {@link Publisher} in case the item from this {@link Mono} has - * not been emitted before the given {@link Publisher} emits. - * - *

- * - * - * @param firstTimeout the timeout - * {@link Publisher} that must not emit before the first signal from this {@link Mono} - * @param fallback the fallback {@link Publisher} to subscribe when a timeout occurs - * @param the element type of the timeout Publisher - * - * @return an expirable {@link Mono} with a fallback {@link Mono} if the item doesn't - * come before a {@link Publisher} signals - * - */ - public final Mono timeout(Publisher firstTimeout, Mono fallback) { - return onAssembly(new MonoTimeout<>(this, firstTimeout, fallback)); - } - - /** - * If this {@link Mono} is valued, emit a {@link reactor.util.function.Tuple2} pair of - * T1 the current clock time in millis (as a {@link Long} measured by the - * {@link Schedulers#parallel() parallel} Scheduler) and T2 the emitted data (as a {@code T}). - * - *

- * - * - * @return a timestamped {@link Mono} - * @see #timed() - */ - public final Mono> timestamp() { - return timestamp(Schedulers.parallel()); - } - - /** - * If this {@link Mono} is valued, emit a {@link reactor.util.function.Tuple2} pair of - * T1 the current clock time in millis (as a {@link Long} measured by the - * provided {@link Scheduler}) and T2 the emitted data (as a {@code T}). - * - *

The provider {@link Scheduler} will be asked to {@link Scheduler#now(TimeUnit) provide time} - * with a granularity of {@link TimeUnit#MILLISECONDS}. In order for this operator to work as advertised, the - * provided Scheduler should thus return results that can be interpreted as unix timestamps.

- *

- * - * - * - * @param scheduler a {@link Scheduler} instance to read time from - * @return a timestamped {@link Mono} - * @see Scheduler#now(TimeUnit) - * @see #timed(Scheduler) - */ - public final Mono> timestamp(Scheduler scheduler) { - Objects.requireNonNull(scheduler, "scheduler"); - return map(d -> Tuples.of(scheduler.now(TimeUnit.MILLISECONDS), d)); - } - - /** - * Transform this {@link Mono} into a {@link CompletableFuture} completing on onNext or onComplete and failing on - * onError. - * - *

- * - * - * @return a {@link CompletableFuture} - */ - public final CompletableFuture toFuture() { - return subscribeWith(new MonoToCompletableFuture<>(false)); - } - - /** - * Transform this {@link Mono} in order to generate a target {@link Mono}. Unlike {@link #transformDeferred(Function)}, the - * provided function is executed as part of assembly. - * - *

-	 * Function applySchedulers = mono -> mono.subscribeOn(Schedulers.io())
-	 *                                                    .publishOn(Schedulers.parallel());
-	 * mono.transform(applySchedulers).map(v -> v * v).subscribe();
-	 * 
- *

- * - * - * @param transformer the {@link Function} to immediately map this {@link Mono} into a target {@link Mono} - * instance. - * @param the item type in the returned {@link Mono} - * - * @return a new {@link Mono} - * @see #transformDeferred(Function) transformDeferred(Function) for deferred composition of Mono for each Subscriber - * @see #as(Function) as(Function) for a loose conversion to an arbitrary type - */ - @SuppressWarnings({"unchecked", "rawtypes"}) - public final Mono transform(Function, ? extends Publisher> transformer) { - if (Hooks.DETECT_CONTEXT_LOSS) { - transformer = new ContextTrackingFunctionWrapper(transformer); - } - return onAssembly(from(transformer.apply(this))); - } - - /** - * Defer the given transformation to this {@link Mono} in order to generate a - * target {@link Mono} type. A transformation will occur for each - * {@link Subscriber}. For instance: - * - *

-	 * mono.transformDeferred(original -> original.log());
-	 * 
- *

- * - * - * @param transformer the {@link Function} to lazily map this {@link Mono} into a target {@link Mono} - * instance upon subscription. - * @param the item type in the returned {@link Publisher} - * - * @return a new {@link Mono} - * @see #transform(Function) transform(Function) for immmediate transformation of Mono - * @see #transformDeferredContextual(BiFunction) transformDeferredContextual(BiFunction) for a similarly deferred transformation of Mono reading the ContextView - * @see #as(Function) as(Function) for a loose conversion to an arbitrary type - */ - public final Mono transformDeferred(Function, ? extends Publisher> transformer) { - return defer(() -> { - if (Hooks.DETECT_CONTEXT_LOSS) { - @SuppressWarnings({"unchecked", "rawtypes"}) - Mono result = from(new ContextTrackingFunctionWrapper((Function) transformer).apply(this)); - return result; - } - return from(transformer.apply(this)); - }); - } - - /** - * Defer the given transformation to this {@link Mono} in order to generate a - * target {@link Mono} type. A transformation will occur for each - * {@link Subscriber}. In addition, the transforming {@link BiFunction} exposes - * the {@link ContextView} of each {@link Subscriber}. For instance: - * - *

-	 * Mono<T> monoLogged = mono.transformDeferredContextual((original, ctx) -> original.log("for RequestID" + ctx.get("RequestID"))
-	 * //...later subscribe. Each subscriber has its Context with a RequestID entry
-	 * monoLogged.contextWrite(Context.of("RequestID", "requestA").subscribe();
-	 * monoLogged.contextWrite(Context.of("RequestID", "requestB").subscribe();
-	 * 
- *

- * - * - * @param transformer the {@link BiFunction} to lazily map this {@link Mono} into a target {@link Mono} - * instance upon subscription, with access to {@link ContextView} - * @param the item type in the returned {@link Publisher} - * @return a new {@link Mono} - * @see #transform(Function) transform(Function) for immmediate transformation of Mono - * @see #transformDeferred(Function) transformDeferred(Function) for a similarly deferred transformation of Mono without the ContextView - * @see #as(Function) as(Function) for a loose conversion to an arbitrary type - */ - public final Mono transformDeferredContextual(BiFunction, ? super ContextView, ? extends Publisher> transformer) { - return deferContextual(ctxView -> { - if (Hooks.DETECT_CONTEXT_LOSS) { - ContextTrackingFunctionWrapper wrapper = new ContextTrackingFunctionWrapper<>( - publisher -> transformer.apply(wrap(publisher, false), ctxView), - transformer.toString() - ); - return wrap(wrapper.apply(this), true); - } - return from(transformer.apply(this, ctxView)); - }); - } - - /** - * Wait for the result from this mono, use it to create a second mono via the - * provided {@code rightGenerator} function and combine both results into a {@link Tuple2}. - * - *

- * - * - * @param rightGenerator the {@link Function} to generate a {@code Mono} to combine with - * @param the element type of the other Mono instance - * - * @return a new combined Mono - */ - public final Mono> zipWhen(Function> rightGenerator) { - return zipWhen(rightGenerator, Tuples::of); - } - - /** - * Wait for the result from this mono, use it to create a second mono via the - * provided {@code rightGenerator} function and combine both results into an arbitrary - * {@code O} object, as defined by the provided {@code combinator} function. - * - *

- * - * - * @param rightGenerator the {@link Function} to generate a {@code Mono} to combine with - * @param combinator a {@link BiFunction} combinator function when both sources complete - * @param the element type of the other Mono instance - * @param the element type of the combination - * - * @return a new combined Mono - */ - public final Mono zipWhen(Function> rightGenerator, - BiFunction combinator) { - Objects.requireNonNull(rightGenerator, "rightGenerator function is mandatory to get the right-hand side Mono"); - Objects.requireNonNull(combinator, "combinator function is mandatory to combine results from both Monos"); - return flatMap(t -> rightGenerator.apply(t).map(t2 -> combinator.apply(t, t2))); - } - - /** - * Combine the result from this mono and another into a {@link Tuple2}. - *

- * An error or empty completion of any source will cause the other source - * to be cancelled and the resulting Mono to immediately error or complete, respectively. - * - *

- * - * - * @param other the {@link Mono} to combine with - * @param the element type of the other Mono instance - * - * @return a new combined Mono - */ - public final Mono> zipWith(Mono other) { - return zipWith(other, Flux.tuple2Function()); - } - - /** - * Combine the result from this mono and another into an arbitrary {@code O} object, - * as defined by the provided {@code combinator} function. - *

- * An error or empty completion of any source will cause the other source - * to be cancelled and the resulting Mono to immediately error or complete, respectively. - * - *

- * - * - * @param other the {@link Mono} to combine with - * @param combinator a {@link BiFunction} combinator function when both sources - * complete - * @param the element type of the other Mono instance - * @param the element type of the combination - * - * @return a new combined Mono - */ - public final Mono zipWith(Mono other, - BiFunction combinator) { - if (this instanceof MonoZip) { - @SuppressWarnings("unchecked") MonoZip o = (MonoZip) this; - Mono result = o.zipAdditionalSource(other, combinator); - if (result != null) { - return result; - } - } - - return zip(this, other, combinator); - } - - /** - * To be used by custom operators: invokes assembly {@link Hooks} pointcut given a - * {@link Mono}, potentially returning a new {@link Mono}. This is for example useful - * to activate cross-cutting concerns at assembly time, eg. a generalized - * {@link #checkpoint()}. - * - * @param the value type - * @param source the source to apply assembly hooks onto - * - * @return the source, potentially wrapped with assembly time cross-cutting behavior - */ - @SuppressWarnings("unchecked") - protected static Mono onAssembly(Mono source) { - Function hook = Hooks.onEachOperatorHook; - if(hook != null) { - source = (Mono) hook.apply(source); - } - if (Hooks.GLOBAL_TRACE) { - AssemblySnapshot stacktrace = new AssemblySnapshot(null, Traces.callSiteSupplierFactory.get()); - source = (Mono) Hooks.addAssemblyInfo(source, stacktrace); - } - return source; - } - - @Override - public String toString() { - return getClass().getSimpleName(); - } - - - static Mono empty(Publisher source) { - @SuppressWarnings("unchecked") - Mono then = (Mono)ignoreElements(source); - return then; - } - - static Mono doOnSignal(Mono source, - @Nullable Consumer onSubscribe, - @Nullable Consumer onNext, - @Nullable LongConsumer onRequest, - @Nullable Runnable onCancel) { - if (source instanceof Fuseable) { - return onAssembly(new MonoPeekFuseable<>(source, - onSubscribe, - onNext, - onRequest, - onCancel)); - } - return onAssembly(new MonoPeek<>(source, - onSubscribe, - onNext, - onRequest, - onCancel)); - } - - static Mono doOnTerminalSignal(Mono source, - @Nullable Consumer onSuccess, - @Nullable Consumer onError, - @Nullable BiConsumer onAfterTerminate) { - return onAssembly(new MonoPeekTerminal<>(source, onSuccess, onError, onAfterTerminate)); - } - - /** - * Unchecked wrap of {@link Publisher} as {@link Mono}, supporting {@link Fuseable} sources. - * When converting a {@link Mono} or {@link Mono Monos} that have been converted to a {@link Flux} and back, - * the original {@link Mono} is returned unwrapped. - * Note that this bypasses {@link Hooks#onEachOperator(String, Function) assembly hooks}. - * - * @param source the {@link Publisher} to wrap - * @param enforceMonoContract {@code} true to wrap publishers without assumption about their cardinality - * (first {@link Subscriber#onNext(Object)} will cancel the source), {@code false} to behave like {@link #fromDirect(Publisher)}. - * @param input upstream type - * @return a wrapped {@link Mono} - */ - static Mono wrap(Publisher source, boolean enforceMonoContract) { - //some sources can be considered already assembled monos - //all conversion methods (from, fromDirect, wrap) must accommodate for this - if (source instanceof Mono) { - return (Mono) source; - } - if (source instanceof FluxSourceMono - || source instanceof FluxSourceMonoFuseable) { - @SuppressWarnings("unchecked") - Mono extracted = (Mono) ((FluxFromMonoOperator) source).source; - return extracted; - } - - //equivalent to what from used to be, without assembly hooks - if (enforceMonoContract) { - if (source instanceof Flux && source instanceof Callable) { - @SuppressWarnings("unchecked") Callable m = (Callable) source; - return Flux.wrapToMono(m); - } - if (source instanceof Flux) { - return new MonoNext<>((Flux) source); - } - return new MonoFromPublisher<>(source); - } - - //equivalent to what fromDirect used to be without onAssembly - if(source instanceof Flux && source instanceof Fuseable) { - return new MonoSourceFluxFuseable<>((Flux) source); - } - if (source instanceof Flux) { - return new MonoSourceFlux<>((Flux) source); - } - if(source instanceof Fuseable) { - return new MonoSourceFuseable<>(source); - } - return new MonoSource<>(source); - } - - @SuppressWarnings("unchecked") - static BiPredicate equalsBiPredicate(){ - return EQUALS_BIPREDICATE; - } - static final BiPredicate EQUALS_BIPREDICATE = Object::equals; -} +/* + * Copyright (c) 2016-2023 VMware Inc. or its affiliates, All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package reactor.core.publisher; + +import java.time.Duration; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.Spliterator; +import java.util.concurrent.Callable; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.BiPredicate; +import java.util.function.BooleanSupplier; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.LongConsumer; +import java.util.function.Predicate; +import java.util.function.Supplier; +import java.util.logging.Level; + +import io.micrometer.core.instrument.MeterRegistry; +import org.reactivestreams.Publisher; +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; + +import reactor.core.CorePublisher; +import reactor.core.CoreSubscriber; +import reactor.core.Disposable; +import reactor.core.Exceptions; +import reactor.core.Fuseable; +import reactor.core.Scannable; +import reactor.core.publisher.FluxOnAssembly.AssemblySnapshot; +import reactor.core.publisher.FluxOnAssembly.CheckpointHeavySnapshot; +import reactor.core.publisher.FluxOnAssembly.CheckpointLightSnapshot; +import reactor.core.scheduler.Scheduler; +import reactor.core.scheduler.Scheduler.Worker; +import reactor.core.scheduler.Schedulers; +import reactor.util.Logger; +import reactor.util.Metrics; +import reactor.util.annotation.Nullable; +import reactor.util.concurrent.Queues; +import reactor.util.context.Context; +import reactor.util.context.ContextView; +import reactor.util.function.Tuple2; +import reactor.util.function.Tuple3; +import reactor.util.function.Tuple4; +import reactor.util.function.Tuple5; +import reactor.util.function.Tuple6; +import reactor.util.function.Tuple7; +import reactor.util.function.Tuple8; +import reactor.util.function.Tuples; +import reactor.core.observability.SignalListener; +import reactor.core.observability.SignalListenerFactory; +import reactor.util.retry.Retry; + +/** + * A Reactive Streams {@link Publisher} with basic rx operators that emits at most one item via the + * {@code onNext} signal then terminates with an {@code onComplete} signal (successful Mono, + * with or without value), or only emits a single {@code onError} signal (failed Mono). + * + *

Most Mono implementations are expected to immediately call {@link Subscriber#onComplete()} + * after having called {@link Subscriber#onNext(T)}. {@link Mono#never() Mono.never()} is an outlier: it doesn't + * emit any signal, which is not technically forbidden although not terribly useful outside + * of tests. On the other hand, a combination of {@code onNext} and {@code onError} is explicitly forbidden. + * + *

+ * The recommended way to learn about the {@link Mono} API and discover new operators is + * through the reference documentation, rather than through this javadoc (as opposed to + * learning more about individual operators). See the + * "which operator do I need?" appendix. + * + *

+ * + *

+ * + *

The rx operators will offer aliases for input {@link Mono} type to preserve the "at most one" + * property of the resulting {@link Mono}. For instance {@link Mono#flatMap flatMap} returns a + * {@link Mono}, while there is a {@link Mono#flatMapMany flatMapMany} alias with possibly more than + * 1 emission. + * + *

{@code Mono} should be used for {@link Publisher} that just completes without any value. + * + *

It is intended to be used in implementations and return types, input parameters should keep + * using raw {@link Publisher} as much as possible. + * + *

Note that using state in the {@code java.util.function} / lambdas used within Mono operators + * should be avoided, as these may be shared between several {@link Subscriber Subscribers}. + * + * @param the type of the single value of this class + * @author Sebastien Deleuze + * @author Stephane Maldini + * @author David Karnok + * @author Simon Baslé + * @see Flux + */ +public abstract class Mono implements CorePublisher { + +// ============================================================================================================== +// Static Generators +// ============================================================================================================== + + /** + * Creates a deferred emitter that can be used with callback-based + * APIs to signal at most one value, a complete or an error signal. + *

+ * + *

+ * Bridging legacy API involves mostly boilerplate code due to the lack + * of standard types and methods. There are two kinds of API surfaces: + * 1) addListener/removeListener and 2) callback-handler. + *

+ * 1) addListener/removeListener pairs
+ * To work with such API one has to instantiate the listener, + * call the sink from the listener then register it with the source: + *


+	 * Mono.<String>create(sink -> {
+	 *     HttpListener listener = event -> {
+	 *         if (event.getResponseCode() >= 400) {
+	 *             sink.error(new RuntimeException("Failed"));
+	 *         } else {
+	 *             String body = event.getBody();
+	 *             if (body.isEmpty()) {
+	 *                 sink.success();
+	 *             } else {
+	 *                 sink.success(body.toLowerCase());
+	 *             }
+	 *         }
+	 *     };
+	 *
+	 *     client.addListener(listener);
+	 *
+	 *     sink.onDispose(() -> client.removeListener(listener));
+	 * });
+	 * 
+ * Note that this works only with single-value emitting listeners. Otherwise, + * all subsequent signals are dropped. You may have to add {@code client.removeListener(this);} + * to the listener's body. + *

+ * 2) callback handler
+ * This requires a similar instantiation pattern such as above, but usually the + * successful completion and error are separated into different methods. + * In addition, the legacy API may or may not support some cancellation mechanism. + *


+	 * Mono.<String>create(sink -> {
+	 *     Callback<String> callback = new Callback<String>() {
+	 *         @Override
+	 *         public void onResult(String data) {
+	 *             sink.success(data.toLowerCase());
+	 *         }
+	 *
+	 *         @Override
+	 *         public void onError(Exception e) {
+	 *             sink.error(e);
+	 *         }
+	 *     }
+	 *
+	 *     // without cancellation support:
+	 *
+	 *     client.call("query", callback);
+	 *
+	 *     // with cancellation support:
+	 *
+	 *     AutoCloseable cancel = client.call("query", callback);
+	 *     sink.onDispose(() -> {
+	 *         try {
+	 *             cancel.close();
+	 *         } catch (Exception ex) {
+	 *             Exceptions.onErrorDropped(ex);
+	 *         }
+	 *     });
+	 * });
+	 * 
+ * @param callback Consume the {@link MonoSink} provided per-subscriber by Reactor to generate signals. + * @param The type of the value emitted + * @return a {@link Mono} + */ + public static Mono create(Consumer> callback) { + return onAssembly(new MonoCreate<>(callback)); + } + + /** + * Create a {@link Mono} provider that will {@link Supplier#get supply} a target {@link Mono} to subscribe to for + * each {@link Subscriber} downstream. + * + *

+ * + *

+ * @param supplier a {@link Mono} factory + * @param the element type of the returned Mono instance + * @return a deferred {@link Mono} + * @see #deferContextual(Function) + */ + public static Mono defer(Supplier> supplier) { + return onAssembly(new MonoDefer<>(supplier)); + } + + /** + * Create a {@link Mono} provider that will {@link Function#apply supply} a target {@link Mono} + * to subscribe to for each {@link Subscriber} downstream. + * This operator behaves the same way as {@link #defer(Supplier)}, + * but accepts a {@link Function} that will receive the current {@link ContextView} as an argument. + * + *

+ * + *

+ * @param contextualMonoFactory a {@link Mono} factory + * @param the element type of the returned Mono instance + * @return a deferred {@link Mono} deriving actual {@link Mono} from context values for each subscription + */ + public static Mono deferContextual(Function> contextualMonoFactory) { + return onAssembly(new MonoDeferContextual<>(contextualMonoFactory)); + } + + /** + * Create a Mono which delays an onNext signal by a given {@link Duration duration} + * on a default Scheduler and completes. + * If the demand cannot be produced in time, an onError will be signalled instead. + * The delay is introduced through the {@link Schedulers#parallel() parallel} default Scheduler. + * + *

+ * + *

+ * @param duration the duration of the delay + * + * @return a new {@link Mono} + */ + public static Mono delay(Duration duration) { + return delay(duration, Schedulers.parallel()); + } + + /** + * Create a Mono which delays an onNext signal by a given {@link Duration duration} + * on a provided {@link Scheduler} and completes. + * If the demand cannot be produced in time, an onError will be signalled instead. + * + *

+ * + *

+ * @param duration the {@link Duration} of the delay + * @param timer a time-capable {@link Scheduler} instance to run on + * + * @return a new {@link Mono} + */ + public static Mono delay(Duration duration, Scheduler timer) { + return onAssembly(new MonoDelay(duration.toNanos(), TimeUnit.NANOSECONDS, timer)); + } + + /** + * Create a {@link Mono} that completes without emitting any item. + * + *

+ * + *

+ * @param the reified {@link Subscriber} type + * + * @return a completed {@link Mono} + */ + public static Mono empty() { + return MonoEmpty.instance(); + } + + /** + * Create a {@link Mono} that terminates with the specified error immediately after + * being subscribed to. + *

+ * + *

+ * @param error the onError signal + * @param the reified {@link Subscriber} type + * + * @return a failing {@link Mono} + */ + public static Mono error(Throwable error) { + return onAssembly(new MonoError<>(error)); + } + + /** + * Create a {@link Mono} that terminates with an error immediately after being + * subscribed to. The {@link Throwable} is generated by a {@link Supplier}, invoked + * each time there is a subscription and allowing for lazy instantiation. + *

+ * + *

+ * @param errorSupplier the error signal {@link Supplier} to invoke for each {@link Subscriber} + * @param the reified {@link Subscriber} type + * + * @return a failing {@link Mono} + */ + public static Mono error(Supplier errorSupplier) { + return onAssembly(new MonoErrorSupplied<>(errorSupplier)); + } + + /** + * Pick the first {@link Mono} to emit any signal (value, empty completion or error) + * and replay that signal, effectively behaving like the fastest of these competing + * sources. + *

+ * + *

+ * @param monos The deferred monos to use. + * @param The type of the function result. + * + * @return a new {@link Mono} behaving like the fastest of its sources. + * @deprecated use {@link #firstWithSignal(Mono[])}. To be removed in reactor 3.5. + */ + @SafeVarargs + @Deprecated + public static Mono first(Mono... monos) { + return firstWithSignal(monos); + } + + /** + * Pick the first {@link Mono} to emit any signal (value, empty completion or error) + * and replay that signal, effectively behaving like the fastest of these competing + * sources. + *

+ * + *

+ * @param monos The deferred monos to use. + * @param The type of the function result. + * + * @return a new {@link Mono} behaving like the fastest of its sources. + * @deprecated use {@link #firstWithSignal(Iterable)}. To be removed in reactor 3.5. + */ + @Deprecated + public static Mono first(Iterable> monos) { + return firstWithSignal(monos); + } + + /** + * Pick the first {@link Mono} to emit any signal (value, empty completion or error) + * and replay that signal, effectively behaving like the fastest of these competing + * sources. + *

+ * + *

+ * @param monos The deferred monos to use. + * @param The type of the function result. + * + * @return a new {@link Mono} behaving like the fastest of its sources. + */ + @SafeVarargs + public static Mono firstWithSignal(Mono... monos) { + return onAssembly(new MonoFirstWithSignal<>(monos)); + } + + /** + * Pick the first {@link Mono} to emit any signal (value, empty completion or error) + * and replay that signal, effectively behaving like the fastest of these competing + * sources. + *

+ * + *

+ * @param monos The deferred monos to use. + * @param The type of the function result. + * + * @return a new {@link Mono} behaving like the fastest of its sources. + */ + public static Mono firstWithSignal(Iterable> monos) { + return onAssembly(new MonoFirstWithSignal<>(monos)); + } + + /** + * Pick the first {@link Mono} source to emit any value and replay that signal, + * effectively behaving like the source that first emits an + * {@link Subscriber#onNext(Object) onNext}. + * + *

+ * Valued sources always "win" over an empty source (one that only emits onComplete) + * or a failing source (one that only emits onError). + *

+ * When no source can provide a value, this operator fails with a {@link NoSuchElementException} + * (provided there are at least two sources). This exception has a {@link Exceptions#multiple(Throwable...) composite} + * as its {@link Throwable#getCause() cause} that can be used to inspect what went wrong with each source + * (so the composite has as many elements as there are sources). + *

+ * Exceptions from failing sources are directly reflected in the composite at the index of the failing source. + * For empty sources, a {@link NoSuchElementException} is added at their respective index. + * One can use {@link Exceptions#unwrapMultiple(Throwable) Exceptions.unwrapMultiple(topLevel.getCause())} + * to easily inspect these errors as a {@link List}. + *

+ * Note that like in {@link #firstWithSignal(Iterable)}, an infinite source can be problematic + * if no other source emits onNext. + *

+ * + * + * @param monos An {@link Iterable} of the competing source monos + * @param The type of the element in the sources and the resulting mono + * + * @return a new {@link Mono} behaving like the fastest of its sources + */ + public static Mono firstWithValue(Iterable> monos) { + return onAssembly(new MonoFirstWithValue<>(monos)); + } + + /** + * Pick the first {@link Mono} source to emit any value and replay that signal, + * effectively behaving like the source that first emits an + * {@link Subscriber#onNext(Object) onNext}. + *

+ * Valued sources always "win" over an empty source (one that only emits onComplete) + * or a failing source (one that only emits onError). + *

+ * When no source can provide a value, this operator fails with a {@link NoSuchElementException} + * (provided there are at least two sources). This exception has a {@link Exceptions#multiple(Throwable...) composite} + * as its {@link Throwable#getCause() cause} that can be used to inspect what went wrong with each source + * (so the composite has as many elements as there are sources). + *

+ * Exceptions from failing sources are directly reflected in the composite at the index of the failing source. + * For empty sources, a {@link NoSuchElementException} is added at their respective index. + * One can use {@link Exceptions#unwrapMultiple(Throwable) Exceptions.unwrapMultiple(topLevel.getCause())} + * to easily inspect these errors as a {@link List}. + *

+ * Note that like in {@link #firstWithSignal(Mono[])}, an infinite source can be problematic + * if no other source emits onNext. + * In case the {@code first} source is already an array-based {@link #firstWithValue(Mono, Mono[])} + * instance, nesting is avoided: a single new array-based instance is created with all the + * sources from {@code first} plus all the {@code others} sources at the same level. + *

+ * + * + * @param first the first competing source {@link Mono} + * @param others the other competing sources {@link Mono} + * @param The type of the element in the sources and the resulting mono + * + * @return a new {@link Mono} behaving like the fastest of its sources + */ + @SafeVarargs + public static Mono firstWithValue(Mono first, Mono... others) { + if (first instanceof MonoFirstWithValue) { + @SuppressWarnings("unchecked") + MonoFirstWithValue a = (MonoFirstWithValue) first; + Mono result = a.firstValuedAdditionalSources(others); + if (result != null) { + return result; + } + } + return onAssembly(new MonoFirstWithValue<>(first, others)); + } + + /** + * Expose the specified {@link Publisher} with the {@link Mono} API, and ensure it will emit 0 or 1 item. + * The source emitter will be cancelled on the first `onNext`. + *

+ * + *

+ * {@link Hooks#onEachOperator(String, Function)} and similar assembly hooks are applied + * unless the source is already a {@link Mono} (including {@link Mono} that was decorated as a {@link Flux}, + * see {@link Flux#from(Publisher)}). + * + * @param source the {@link Publisher} source + * @param the source type + * + * @return the next item emitted as a {@link Mono} + */ + public static Mono from(Publisher source) { + //some sources can be considered already assembled monos + //all conversion methods (from, fromDirect, wrap) must accommodate for this + if (source instanceof Mono) { + @SuppressWarnings("unchecked") + Mono casted = (Mono) source; + return casted; + } + if (source instanceof FluxSourceMono + || source instanceof FluxSourceMonoFuseable) { + @SuppressWarnings("unchecked") + FluxFromMonoOperator wrapper = (FluxFromMonoOperator) source; + @SuppressWarnings("unchecked") + Mono extracted = (Mono) wrapper.source; + return extracted; + } + + //we delegate to `wrap` and apply assembly hooks + @SuppressWarnings("unchecked") Publisher downcasted = (Publisher) source; + return onAssembly(wrap(downcasted, true)); + } + + /** + * Create a {@link Mono} producing its value using the provided {@link Callable}. If + * the Callable resolves to {@code null}, the resulting Mono completes empty. + * + *

+ * + *

+ * @param supplier {@link Callable} that will produce the value + * @param type of the expected value + * + * @return A {@link Mono}. + */ + public static Mono fromCallable(Callable supplier) { + return onAssembly(new MonoCallable<>(supplier)); + } + + /** + * Create a {@link Mono}, producing its value using the provided {@link CompletionStage}. + * + *

+ * + *

+ * If the completionStage is also a {@link Future}, cancelling the Mono will cancel the future. + * Use {@link #fromFuture(CompletableFuture, boolean)} with {@code suppressCancellation} set to + * {@code true} if you need to suppress cancellation propagation. + * + * @param completionStage {@link CompletionStage} that will produce a value (or a null to + * complete immediately) + * @param type of the expected value + * @return A {@link Mono}. + */ + public static Mono fromCompletionStage(CompletionStage completionStage) { + return onAssembly(new MonoCompletionStage<>(completionStage, false)); + } + + /** + * Create a {@link Mono} that wraps a lazily-supplied {@link CompletionStage} on subscription, + * emitting the value produced by the {@link CompletionStage}. + * + *

+ * + *

+ * If the completionStage is also a {@link Future}, cancelling the Mono will cancel the future. + * Use {@link #fromFuture(CompletableFuture, boolean)} with {@code suppressCancellation} set to + * {@code true} if you need to suppress cancellation propagation. + * + * @param stageSupplier The {@link Supplier} of a {@link CompletionStage} that will produce a value (or a null to + * complete immediately). This allows lazy triggering of CompletionStage-based APIs. + * @param type of the expected value + * @return A {@link Mono}. + */ + public static Mono fromCompletionStage(Supplier> stageSupplier) { + return defer(() -> onAssembly(new MonoCompletionStage<>(stageSupplier.get(), false))); + } + + /** + * Convert a {@link Publisher} to a {@link Mono} without any cardinality check + * (ie this method doesn't cancel the source past the first element). + * Conversion transparently returns {@link Mono} sources without wrapping and otherwise + * supports {@link Fuseable} sources. + * Note this is an advanced interoperability operator that implies you know the + * {@link Publisher} you are converting follows the {@link Mono} semantics and only + * ever emits one element. + *

+ * {@link Hooks#onEachOperator(String, Function)} and similar assembly hooks are applied + * unless the source is already a {@link Mono}. + * + * @param source the Mono-compatible {@link Publisher} to wrap + * @param type of the value emitted by the publisher + * @return a wrapped {@link Mono} + */ + public static Mono fromDirect(Publisher source){ + //some sources can be considered already assembled monos + //all conversion methods (from, fromDirect, wrap) must accommodate for this + if(source instanceof Mono){ + @SuppressWarnings("unchecked") + Mono m = (Mono)source; + return m; + } + if (source instanceof FluxSourceMono + || source instanceof FluxSourceMonoFuseable) { + @SuppressWarnings("unchecked") + FluxFromMonoOperator wrapper = (FluxFromMonoOperator) source; + @SuppressWarnings("unchecked") + Mono extracted = (Mono) wrapper.source; + return extracted; + } + + //we delegate to `wrap` and apply assembly hooks + @SuppressWarnings("unchecked") Publisher downcasted = (Publisher) source; + return onAssembly(wrap(downcasted, false)); + } + + /** + * Create a {@link Mono}, producing its value using the provided {@link CompletableFuture} + * and cancelling the future if the Mono gets cancelled. + * + *

+ * + *

+ * Use {@link #fromFuture(CompletableFuture, boolean)} with {@code suppressCancellation} set to + * {@code true} if you need to suppress cancellation propagation. + * + * @param future {@link CompletableFuture} that will produce a value (or a null to + * complete immediately) + * @param type of the expected value + * @return A {@link Mono}. + * @see #fromCompletionStage(CompletionStage) fromCompletionStage for a generalization + */ + public static Mono fromFuture(CompletableFuture future) { + return fromFuture(future, false); + } + + /** + * Create a {@link Mono}, producing its value using the provided {@link CompletableFuture} + * and optionally cancelling the future if the Mono gets cancelled (if {@code suppressCancel == false}). + * + *

+ * + *

+ * + * @param future {@link CompletableFuture} that will produce a value (or a null to complete immediately) + * @param suppressCancel {@code true} to prevent cancellation of the future when the Mono is cancelled, + * {@code false} otherwise (the default) + * @param type of the expected value + * @return A {@link Mono}. + */ + public static Mono fromFuture(CompletableFuture future, boolean suppressCancel) { + return onAssembly(new MonoCompletionStage<>(future, suppressCancel)); + } + + /** + * Create a {@link Mono} that wraps a lazily-supplied {@link CompletableFuture} on subscription, + * emitting the value produced by the future and cancelling the future if the Mono gets cancelled. + * + *

+ * + *

+ * + * @param futureSupplier The {@link Supplier} of a {@link CompletableFuture} that will produce a value + * (or a null to complete immediately). This allows lazy triggering of future-based APIs. + * @param type of the expected value + * @return A {@link Mono}. + * @see #fromCompletionStage(Supplier) fromCompletionStage for a generalization + */ + public static Mono fromFuture(Supplier> futureSupplier) { + return fromFuture(futureSupplier, false); + } + + /** + * Create a {@link Mono} that wraps a lazily-supplied {@link CompletableFuture} on subscription, + * emitting the value produced by the future and optionally cancelling the future if the Mono gets cancelled + * (if {@code suppressCancel == false}). + * + *

+ * + *

+ * + * @param futureSupplier The {@link Supplier} of a {@link CompletableFuture} that will produce a value + * (or a null to complete immediately). This allows lazy triggering of future-based APIs. + * @param suppressCancel {@code true} to prevent cancellation of the future when the Mono is cancelled, + * {@code false} otherwise (the default) + * @param type of the expected value + * @return A {@link Mono}. + * @see #fromCompletionStage(Supplier) fromCompletionStage for a generalization + */ + public static Mono fromFuture(Supplier> futureSupplier, boolean suppressCancel) { + return defer(() -> onAssembly(new MonoCompletionStage<>(futureSupplier.get(), suppressCancel))); + } + + /** + * Create a {@link Mono} that completes empty once the provided {@link Runnable} has + * been executed. + * + *

+ * + *

+ * @param runnable {@link Runnable} that will be executed before emitting the completion signal + * + * @param The generic type of the upstream, which is preserved by this operator + * @return A {@link Mono}. + */ + public static Mono fromRunnable(Runnable runnable) { + return onAssembly(new MonoRunnable<>(runnable)); + } + + /** + * Create a {@link Mono}, producing its value using the provided {@link Supplier}. If + * the Supplier resolves to {@code null}, the resulting Mono completes empty. + * + *

+ * + *

+ * @param supplier {@link Supplier} that will produce the value + * @param type of the expected value + * + * @return A {@link Mono}. + */ + public static Mono fromSupplier(Supplier supplier) { + return onAssembly(new MonoSupplier<>(supplier)); + } + + + /** + * Create a new {@link Mono} that ignores elements from the source (dropping them), + * but completes when the source completes. + * + *

+ * + *

+ * + *

Discard Support: This operator discards the element from the source. + * + * @param source the {@link Publisher} to ignore + * @param the source type of the ignored data + * + * @return a new completable {@link Mono}. + */ + public static Mono ignoreElements(Publisher source) { + return onAssembly(new MonoIgnorePublisher<>(source)); + } + + /** + * Create a new {@link Mono} that emits the specified item, which is captured at + * instantiation time. + * + *

+ * + *

+ * @param data the only item to onNext + * @param the type of the produced item + * + * @return a {@link Mono}. + */ + public static Mono just(T data) { + return onAssembly(new MonoJust<>(data)); + } + + /** + * Create a new {@link Mono} that emits the specified item if {@link Optional#isPresent()} otherwise only emits + * onComplete. + * + *

+ * + *

+ * @param data the {@link Optional} item to onNext or onComplete if not present + * @param the type of the produced item + * + * @return a {@link Mono}. + */ + public static Mono justOrEmpty(@Nullable Optional data) { + return data != null && data.isPresent() ? just(data.get()) : empty(); + } + + /** + * Create a new {@link Mono} that emits the specified item if non null otherwise only emits + * onComplete. + * + *

+ * + *

+ * @param data the item to onNext or onComplete if null + * @param the type of the produced item + * + * @return a {@link Mono}. + */ + public static Mono justOrEmpty(@Nullable T data) { + return data != null ? just(data) : empty(); + } + + + /** + * Return a {@link Mono} that will never signal any data, error or completion signal, + * essentially running indefinitely. + *

+ * + *

+ * @param the {@link Subscriber} type target + * + * @return a never completing {@link Mono} + */ + public static Mono never() { + return MonoNever.instance(); + } + + /** + * Returns a Mono that emits a Boolean value that indicates whether two Publisher sequences are the + * same by comparing the items emitted by each Publisher pairwise. + *

+ * + * + * @param source1 the first Publisher to compare + * @param source2 the second Publisher to compare + * @param the type of items emitted by each Publisher + * @return a Mono that emits a Boolean value that indicates whether the two sequences are the same + */ + public static Mono sequenceEqual(Publisher source1, Publisher source2) { + return sequenceEqual(source1, source2, equalsBiPredicate(), Queues.SMALL_BUFFER_SIZE); + } + + /** + * Returns a Mono that emits a Boolean value that indicates whether two Publisher sequences are the + * same by comparing the items emitted by each Publisher pairwise based on the results of a specified + * equality function. + *

+ * + * + * @param source1 the first Publisher to compare + * @param source2 the second Publisher to compare + * @param isEqual a function used to compare items emitted by each Publisher + * @param the type of items emitted by each Publisher + * @return a Mono that emits a Boolean value that indicates whether the two Publisher two sequences + * are the same according to the specified function + */ + public static Mono sequenceEqual(Publisher source1, Publisher source2, + BiPredicate isEqual) { + return sequenceEqual(source1, source2, isEqual, Queues.SMALL_BUFFER_SIZE); + } + + /** + * Returns a Mono that emits a Boolean value that indicates whether two Publisher sequences are the + * same by comparing the items emitted by each Publisher pairwise based on the results of a specified + * equality function. + *

+ * + * + * @param source1 the first Publisher to compare + * @param source2 the second Publisher to compare + * @param isEqual a function used to compare items emitted by each Publisher + * @param prefetch the number of items to prefetch from the first and second source Publisher + * @param the type of items emitted by each Publisher + * @return a Mono that emits a Boolean value that indicates whether the two Publisher two sequences + * are the same according to the specified function + */ + public static Mono sequenceEqual(Publisher source1, + Publisher source2, + BiPredicate isEqual, int prefetch) { + return onAssembly(new MonoSequenceEqual<>(source1, source2, isEqual, prefetch)); + } + + /** + * Uses a resource, generated by a supplier for each individual Subscriber, while streaming the value from a + * Mono derived from the same resource and makes sure the resource is released if the + * sequence terminates or the Subscriber cancels. + *

+ *

    + *
  • For eager cleanup, unlike in {@link Flux#using(Callable, Function, Consumer, boolean) Flux}, + * in the case of a valued {@link Mono} the cleanup happens just before passing the value to downstream. + * In all cases, exceptions raised by the eager cleanup {@link Consumer} may override the terminal event, + * discarding the element if the derived {@link Mono} was valued.
  • + *
  • Non-eager cleanup will drop any exception.
  • + *
+ *

+ * + * + * @param resourceSupplier a {@link Callable} that is called on subscribe to create the resource + * @param sourceSupplier a {@link Mono} factory to create the Mono depending on the created resource + * @param resourceCleanup invoked on completion to clean-up the resource + * @param eager set to true to clean before any signal (including onNext) is passed downstream + * @param emitted type + * @param resource type + * + * @return new {@link Mono} + */ + public static Mono using(Callable resourceSupplier, + Function> sourceSupplier, + Consumer resourceCleanup, + boolean eager) { + return onAssembly(new MonoUsing<>(resourceSupplier, sourceSupplier, + resourceCleanup, eager)); + } + + /** + * Uses a resource, generated by a supplier for each individual Subscriber, while streaming the value from a + * Mono derived from the same resource and makes sure the resource is released if the + * sequence terminates or the Subscriber cancels. + *

+ * Unlike in {@link Flux#using(Callable, Function, Consumer) Flux}, in the case of a valued {@link Mono} the cleanup + * happens just before passing the value to downstream. In all cases, exceptions raised by the cleanup + * {@link Consumer} may override the terminal event, discarding the element if the derived {@link Mono} was valued. + *

+ * + * + * @param resourceSupplier a {@link Callable} that is called on subscribe to create the resource + * @param sourceSupplier a {@link Mono} factory to create the Mono depending on the created resource + * @param resourceCleanup invoked on completion to clean-up the resource + * @param emitted type + * @param resource type + * + * @return new {@link Mono} + */ + public static Mono using(Callable resourceSupplier, + Function> sourceSupplier, + Consumer resourceCleanup) { + return using(resourceSupplier, sourceSupplier, resourceCleanup, true); + } + + + /** + * Uses a resource, generated by a {@link Publisher} for each individual {@link Subscriber}, + * to derive a {@link Mono}. Note that all steps of the operator chain that would need the + * resource to be in an open stable state need to be described inside the {@code resourceClosure} + * {@link Function}. + *

+ * Unlike in {@link Flux#usingWhen(Publisher, Function, Function) the Flux counterpart}, ALL signals are deferred + * until the {@link Mono} terminates and the relevant {@link Function} generates and invokes a "cleanup" + * {@link Publisher}. This is because a failure in the cleanup Publisher + * must result in a lone {@code onError} signal in the downstream {@link Mono} (any potential value in the + * derived {@link Mono} is discarded). Here are the various scenarios that can play out: + *

    + *
  • empty Mono, asyncCleanup ends with {@code onComplete()}: downstream receives {@code onComplete()}
  • + *
  • empty Mono, asyncCleanup ends with {@code onError(t)}: downstream receives {@code onError(t)}
  • + *
  • valued Mono, asyncCleanup ends with {@code onComplete()}: downstream receives {@code onNext(value),onComplete()}
  • + *
  • valued Mono, asyncCleanup ends with {@code onError(t)}: downstream receives {@code onError(t)}, {@code value} is discarded
  • + *
  • error(e) Mono, asyncCleanup ends with {@code onComplete()}: downstream receives {@code onError(e)}
  • + *
  • error(e) Mono, asyncCleanup ends with {@code onError(t)}: downstream receives {@code onError(t)}, t suppressing e
  • + *
+ *

+ * + *

+ * Note that if the resource supplying {@link Publisher} emits more than one resource, the + * subsequent resources are dropped ({@link Operators#onNextDropped(Object, Context)}). If + * the publisher errors AFTER having emitted one resource, the error is also silently dropped + * ({@link Operators#onErrorDropped(Throwable, Context)}). + * An empty completion or error without at least one onNext signal (no resource supplied) + * triggers a short-circuit of the main sequence with the same terminal signal + * (no cleanup is invoked). + * + *

Discard Support: This operator discards any source element if the {@code asyncCleanup} handler fails. + * + * @param resourceSupplier a {@link Publisher} that "generates" the resource, + * subscribed for each subscription to the main sequence + * @param resourceClosure a factory to derive a {@link Mono} from the supplied resource + * @param asyncCleanup an asynchronous resource cleanup invoked when the resource + * closure terminates (with onComplete, onError or cancel) + * @param the type of elements emitted by the resource closure, and thus the main sequence + * @param the type of the resource object + * + * @return a new {@link Mono} built around a "transactional" resource, with deferred emission until the + * asynchronous cleanup sequence completes + */ + public static Mono usingWhen(Publisher resourceSupplier, + Function> resourceClosure, + Function> asyncCleanup) { + return usingWhen(resourceSupplier, resourceClosure, asyncCleanup, + (res, error) -> asyncCleanup.apply(res), + asyncCleanup); + } + + /** + * Uses a resource, generated by a {@link Publisher} for each individual {@link Subscriber}, + * to derive a {@link Mono}.Note that all steps of the operator chain that would need the + * resource to be in an open stable state need to be described inside the {@code resourceClosure} + * {@link Function}. + *

+ * Unlike in {@link Flux#usingWhen(Publisher, Function, Function, BiFunction, Function) the Flux counterpart}, + * ALL signals are deferred until the {@link Mono} terminates and the relevant {@link Function} + * generates and invokes a "cleanup" {@link Publisher}. This is because a failure in the cleanup Publisher + * must result in a lone {@code onError} signal in the downstream {@link Mono} (any potential value in the + * derived {@link Mono} is discarded). Here are the various scenarios that can play out: + *

    + *
  • empty Mono, asyncComplete ends with {@code onComplete()}: downstream receives {@code onComplete()}
  • + *
  • empty Mono, asyncComplete ends with {@code onError(t)}: downstream receives {@code onError(t)}
  • + *
  • valued Mono, asyncComplete ends with {@code onComplete()}: downstream receives {@code onNext(value),onComplete()}
  • + *
  • valued Mono, asyncComplete ends with {@code onError(t)}: downstream receives {@code onError(t)}, {@code value} is discarded
  • + *
  • error(e) Mono, errorComplete ends with {@code onComplete()}: downstream receives {@code onError(e)}
  • + *
  • error(e) Mono, errorComplete ends with {@code onError(t)}: downstream receives {@code onError(t)}, t suppressing e
  • + *
+ *

+ * + *

+ * Individual cleanups can also be associated with mono cancellation and + * error terminations: + *

+ * + *

+ * Note that if the resource supplying {@link Publisher} emits more than one resource, the + * subsequent resources are dropped ({@link Operators#onNextDropped(Object, Context)}). If + * the publisher errors AFTER having emitted one resource, the error is also silently dropped + * ({@link Operators#onErrorDropped(Throwable, Context)}). + * An empty completion or error without at least one onNext signal (no resource supplied) + * triggers a short-circuit of the main sequence with the same terminal signal + * (no cleanup is invoked). + * + *

Discard Support: This operator discards the element if the {@code asyncComplete} handler fails. + * + * @param resourceSupplier a {@link Publisher} that "generates" the resource, + * subscribed for each subscription to the main sequence + * @param resourceClosure a factory to derive a {@link Mono} from the supplied resource + * @param asyncComplete an asynchronous resource cleanup invoked if the resource closure terminates with onComplete + * @param asyncError an asynchronous resource cleanup invoked if the resource closure terminates with onError. + * The terminating error is provided to the {@link BiFunction} + * @param asyncCancel an asynchronous resource cleanup invoked if the resource closure is cancelled. + * When {@code null}, the {@code asyncComplete} path is used instead. + * @param the type of elements emitted by the resource closure, and thus the main sequence + * @param the type of the resource object + * + * @return a new {@link Mono} built around a "transactional" resource, with several + * termination path triggering asynchronous cleanup sequences + * + */ + public static Mono usingWhen(Publisher resourceSupplier, + Function> resourceClosure, + Function> asyncComplete, + BiFunction> asyncError, + //the operator itself accepts null for asyncCancel, but we won't in the public API + Function> asyncCancel) { + return onAssembly(new MonoUsingWhen<>(resourceSupplier, resourceClosure, + asyncComplete, asyncError, asyncCancel)); + } + + /** + * Aggregate given publishers into a new {@literal Mono} that will be fulfilled + * when all of the given {@literal sources} have completed. An error will cause + * pending results to be cancelled and immediate error emission to the returned {@link Mono}. + *

+ * + *

+ * @param sources The sources to use. + * + * @return a {@link Mono}. + */ + public static Mono when(Publisher... sources) { + if (sources.length == 0) { + return empty(); + } + if (sources.length == 1) { + return empty(sources[0]); + } + return onAssembly(new MonoWhen(false, sources)); + } + + + /** + * Aggregate given publishers into a new {@literal Mono} that will be + * fulfilled when all of the given {@literal Publishers} have completed. + * An error will cause pending results to be cancelled and immediate error emission + * to the returned {@link Mono}. + * + *

+ * + *

+ * + * @param sources The sources to use. + * + * @return a {@link Mono}. + */ + public static Mono when(final Iterable> sources) { + return onAssembly(new MonoWhen(false, sources)); + } + + /** + * Aggregate given publishers into a new {@literal Mono} that will be + * fulfilled when all of the given {@literal sources} have completed. Errors from + * the sources are delayed. + * If several Publishers error, the exceptions are combined (as suppressed exceptions on a root exception). + * + *

+ * + *

+ * + * @param sources The sources to use. + * + * @return a {@link Mono}. + */ + public static Mono whenDelayError(final Iterable> sources) { + return onAssembly(new MonoWhen(true, sources)); + } + + /** + * Merge given publishers into a new {@literal Mono} that will be fulfilled when + * all of the given {@literal sources} have completed. Errors from the sources are delayed. + * If several Publishers error, the exceptions are combined (as suppressed exceptions on a root exception). + * + *

+ * + *

+ * @param sources The sources to use. + * + * @return a {@link Mono}. + */ + public static Mono whenDelayError(Publisher... sources) { + if (sources.length == 0) { + return empty(); + } + if (sources.length == 1) { + return empty(sources[0]); + } + return onAssembly(new MonoWhen(true, sources)); + } + + /** + * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} + * have produced an item, aggregating their values into a {@link Tuple2}. + * An error or empty completion of any source will cause other sources + * to be cancelled and the resulting Mono to immediately error or complete, respectively. + * + *

+ * + *

+ * @param p1 The first upstream {@link Publisher} to subscribe to. + * @param p2 The second upstream {@link Publisher} to subscribe to. + * @param type of the value from p1 + * @param type of the value from p2 + * + * @return a {@link Mono}. + */ + public static Mono> zip(Mono p1, Mono p2) { + return zip(p1, p2, Flux.tuple2Function()); + } + + /** + * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} + * have produced an item, aggregating their values as defined by the combinator function. + * An error or empty completion of any source will cause other sources + * to be cancelled and the resulting Mono to immediately error or complete, respectively. + * + *

+ * + *

+ * @param p1 The first upstream {@link Publisher} to subscribe to. + * @param p2 The second upstream {@link Publisher} to subscribe to. + * @param combinator a {@link BiFunction} combinator function when both sources + * complete + * @param type of the value from p1 + * @param type of the value from p2 + * @param output value + * + * @return a {@link Mono}. + */ + public static Mono zip(Mono p1, Mono p2, BiFunction combinator) { + return onAssembly(new MonoZip(false, p1, p2, combinator)); + } + + /** + * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} + * have produced an item, aggregating their values into a {@link Tuple3}. + * An error or empty completion of any source will cause other sources + * to be cancelled and the resulting Mono to immediately error or complete, respectively. + * + *

+ * + *

+ * @param p1 The first upstream {@link Publisher} to subscribe to. + * @param p2 The second upstream {@link Publisher} to subscribe to. + * @param p3 The third upstream {@link Publisher} to subscribe to. + * @param type of the value from p1 + * @param type of the value from p2 + * @param type of the value from p3 + * + * @return a {@link Mono}. + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static Mono> zip(Mono p1, Mono p2, Mono p3) { + return onAssembly(new MonoZip(false, a -> Tuples.fromArray((Object[])a), p1, p2, p3)); + } + + /** + * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} + * have produced an item, aggregating their values into a {@link Tuple4}. + * An error or empty completion of any source will cause other sources + * to be cancelled and the resulting Mono to immediately error or complete, respectively. + * + *

+ * + *

+ * @param p1 The first upstream {@link Publisher} to subscribe to. + * @param p2 The second upstream {@link Publisher} to subscribe to. + * @param p3 The third upstream {@link Publisher} to subscribe to. + * @param p4 The fourth upstream {@link Publisher} to subscribe to. + * @param type of the value from p1 + * @param type of the value from p2 + * @param type of the value from p3 + * @param type of the value from p4 + * + * @return a {@link Mono}. + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static Mono> zip(Mono p1, + Mono p2, + Mono p3, + Mono p4) { + return onAssembly(new MonoZip(false, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4)); + } + + /** + * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} + * have produced an item, aggregating their values into a {@link Tuple5}. + * An error or empty completion of any source will cause other sources + * to be cancelled and the resulting Mono to immediately error or complete, respectively. + * + *

+ * + *

+ * @param p1 The first upstream {@link Publisher} to subscribe to. + * @param p2 The second upstream {@link Publisher} to subscribe to. + * @param p3 The third upstream {@link Publisher} to subscribe to. + * @param p4 The fourth upstream {@link Publisher} to subscribe to. + * @param p5 The fifth upstream {@link Publisher} to subscribe to. + * @param type of the value from p1 + * @param type of the value from p2 + * @param type of the value from p3 + * @param type of the value from p4 + * @param type of the value from p5 + * + * @return a {@link Mono}. + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static Mono> zip(Mono p1, + Mono p2, + Mono p3, + Mono p4, + Mono p5) { + return onAssembly(new MonoZip(false, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5)); + } + + /** + * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} + * have produced an item, aggregating their values into a {@link Tuple6}. + * An error or empty completion of any source will cause other sources + * to be cancelled and the resulting Mono to immediately error or complete, respectively. + * + *

+ * + *

+ * @param p1 The first upstream {@link Publisher} to subscribe to. + * @param p2 The second upstream {@link Publisher} to subscribe to. + * @param p3 The third upstream {@link Publisher} to subscribe to. + * @param p4 The fourth upstream {@link Publisher} to subscribe to. + * @param p5 The fifth upstream {@link Publisher} to subscribe to. + * @param p6 The sixth upstream {@link Publisher} to subscribe to. + * @param type of the value from p1 + * @param type of the value from p2 + * @param type of the value from p3 + * @param type of the value from p4 + * @param type of the value from p5 + * @param type of the value from p6 + * + * @return a {@link Mono}. + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static Mono> zip(Mono p1, + Mono p2, + Mono p3, + Mono p4, + Mono p5, + Mono p6) { + return onAssembly(new MonoZip(false, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5, p6)); + } + + /** + * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} + * have produced an item, aggregating their values into a {@link Tuple7}. + * An error or empty completion of any source will cause other sources + * to be cancelled and the resulting Mono to immediately error or complete, respectively. + * + *

+ * + *

+ * @param p1 The first upstream {@link Publisher} to subscribe to. + * @param p2 The second upstream {@link Publisher} to subscribe to. + * @param p3 The third upstream {@link Publisher} to subscribe to. + * @param p4 The fourth upstream {@link Publisher} to subscribe to. + * @param p5 The fifth upstream {@link Publisher} to subscribe to. + * @param p6 The sixth upstream {@link Publisher} to subscribe to. + * @param p7 The seventh upstream {@link Publisher} to subscribe to. + * @param type of the value from p1 + * @param type of the value from p2 + * @param type of the value from p3 + * @param type of the value from p4 + * @param type of the value from p5 + * @param type of the value from p6 + * @param type of the value from p7 + * + * @return a {@link Mono}. + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static Mono> zip(Mono p1, + Mono p2, + Mono p3, + Mono p4, + Mono p5, + Mono p6, + Mono p7) { + return onAssembly(new MonoZip(false, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5, p6, p7)); + } + + /** + * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} + * have produced an item, aggregating their values into a {@link Tuple8}. + * An error or empty completion of any source will cause other sources + * to be cancelled and the resulting Mono to immediately error or complete, respectively. + * + *

+ * + *

+ * @param p1 The first upstream {@link Publisher} to subscribe to. + * @param p2 The second upstream {@link Publisher} to subscribe to. + * @param p3 The third upstream {@link Publisher} to subscribe to. + * @param p4 The fourth upstream {@link Publisher} to subscribe to. + * @param p5 The fifth upstream {@link Publisher} to subscribe to. + * @param p6 The sixth upstream {@link Publisher} to subscribe to. + * @param p7 The seventh upstream {@link Publisher} to subscribe to. + * @param p8 The eight upstream {@link Publisher} to subscribe to. + * @param type of the value from p1 + * @param type of the value from p2 + * @param type of the value from p3 + * @param type of the value from p4 + * @param type of the value from p5 + * @param type of the value from p6 + * @param type of the value from p7 + * @param type of the value from p8 + * + * @return a {@link Mono}. + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static Mono> zip(Mono p1, + Mono p2, + Mono p3, + Mono p4, + Mono p5, + Mono p6, + Mono p7, + Mono p8) { + return onAssembly(new MonoZip(false, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5, p6, p7, p8)); + } + + /** + * Aggregate given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal + * Monos} have produced an item, aggregating their values according to the provided combinator function. + * An error or empty completion of any source will cause other sources + * to be cancelled and the resulting Mono to immediately error or complete, respectively. + * + *

+ * + *

+ * + * @param monos The monos to use. + * @param combinator the function to transform the combined array into an arbitrary + * object. + * @param the combined result + * + * @return a {@link Mono}. + */ + public static Mono zip(final Iterable> monos, Function combinator) { + return onAssembly(new MonoZip<>(false, combinator, monos)); + } + + /** + * Aggregate given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal + * Monos} have produced an item, aggregating their values according to the provided combinator function. + * An error or empty completion of any source will cause other sources + * to be cancelled and the resulting Mono to immediately error or complete, respectively. + *

+ * + *

+ * @param monos The monos to use. + * @param combinator the function to transform the combined array into an arbitrary + * object. + * @param the combined result + * + * @return a {@link Mono}. + */ + public static Mono zip(Function combinator, Mono... monos) { + if (monos.length == 0) { + return empty(); + } + if (monos.length == 1) { + return monos[0].map(d -> combinator.apply(new Object[]{d})); + } + return onAssembly(new MonoZip<>(false, combinator, monos)); + } + + /** + * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} + * have produced an item, aggregating their values into a {@link Tuple2} and delaying errors. + * If a Mono source completes without value, the other source is run to completion then the + * resulting {@link Mono} completes empty. + * If both Monos error, the two exceptions are combined (as suppressed exceptions on a root exception). + * + *

+ * + *

+ * @param p1 The first upstream {@link Publisher} to subscribe to. + * @param p2 The second upstream {@link Publisher} to subscribe to. + * @param type of the value from p1 + * @param type of the value from p2 + * + * @return a {@link Mono}. + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static Mono> zipDelayError(Mono p1, Mono p2) { + return onAssembly(new MonoZip(true, a -> Tuples.fromArray((Object[])a), p1, p2)); + } + + /** + * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Mono Monos} + * have produced an item, aggregating their values into a {@link Tuple3} and delaying errors. + * If a Mono source completes without value, all other sources are run to completion then + * the resulting {@link Mono} completes empty. + * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). + * + *

+ * + *

+ * @param p1 The first upstream {@link Publisher} to subscribe to. + * @param p2 The second upstream {@link Publisher} to subscribe to. + * @param p3 The third upstream {@link Publisher} to subscribe to. + * @param type of the value from p1 + * @param type of the value from p2 + * @param type of the value from p3 + * + * @return a {@link Mono}. + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static Mono> zipDelayError(Mono p1, Mono p2, Mono p3) { + return onAssembly(new MonoZip(true, a -> Tuples.fromArray((Object[])a), p1, p2, p3)); + } + + /** + * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} + * have produced an item, aggregating their values into a {@link Tuple4} and delaying errors. + * If a Mono source completes without value, all other sources are run to completion then + * the resulting {@link Mono} completes empty. + * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). + * + *

+ * + *

+ * @param p1 The first upstream {@link Publisher} to subscribe to. + * @param p2 The second upstream {@link Publisher} to subscribe to. + * @param p3 The third upstream {@link Publisher} to subscribe to. + * @param p4 The fourth upstream {@link Publisher} to subscribe to. + * @param type of the value from p1 + * @param type of the value from p2 + * @param type of the value from p3 + * @param type of the value from p4 + * + * @return a {@link Mono}. + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static Mono> zipDelayError(Mono p1, + Mono p2, + Mono p3, + Mono p4) { + return onAssembly(new MonoZip(true, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4)); + } + + /** + * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} + * have produced an item, aggregating their values into a {@link Tuple5} and delaying errors. + * If a Mono source completes without value, all other sources are run to completion then + * the resulting {@link Mono} completes empty. + * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). + *

+ * + *

+ * @param p1 The first upstream {@link Publisher} to subscribe to. + * @param p2 The second upstream {@link Publisher} to subscribe to. + * @param p3 The third upstream {@link Publisher} to subscribe to. + * @param p4 The fourth upstream {@link Publisher} to subscribe to. + * @param p5 The fifth upstream {@link Publisher} to subscribe to. + * @param type of the value from p1 + * @param type of the value from p2 + * @param type of the value from p3 + * @param type of the value from p4 + * @param type of the value from p5 + * + * @return a {@link Mono}. + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static Mono> zipDelayError(Mono p1, + Mono p2, + Mono p3, + Mono p4, + Mono p5) { + return onAssembly(new MonoZip(true, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5)); + } + + /** + * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} + * have produced an item, aggregating their values into a {@link Tuple6} and delaying errors. + * If a Mono source completes without value, all other sources are run to completion then + * the resulting {@link Mono} completes empty. + * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). + * + *

+ * + *

+ * @param p1 The first upstream {@link Publisher} to subscribe to. + * @param p2 The second upstream {@link Publisher} to subscribe to. + * @param p3 The third upstream {@link Publisher} to subscribe to. + * @param p4 The fourth upstream {@link Publisher} to subscribe to. + * @param p5 The fifth upstream {@link Publisher} to subscribe to. + * @param p6 The sixth upstream {@link Publisher} to subscribe to. + * @param type of the value from p1 + * @param type of the value from p2 + * @param type of the value from p3 + * @param type of the value from p4 + * @param type of the value from p5 + * @param type of the value from p6 + * + * @return a {@link Mono}. + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static Mono> zipDelayError(Mono p1, + Mono p2, + Mono p3, + Mono p4, + Mono p5, + Mono p6) { + return onAssembly(new MonoZip(true, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5, p6)); + } + + /** + * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} + * have produced an item, aggregating their values into a {@link Tuple7} and delaying errors. + * If a Mono source completes without value, all other sources are run to completion then + * the resulting {@link Mono} completes empty. + * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). + * + *

+ * + *

+ * @param p1 The first upstream {@link Publisher} to subscribe to. + * @param p2 The second upstream {@link Publisher} to subscribe to. + * @param p3 The third upstream {@link Publisher} to subscribe to. + * @param p4 The fourth upstream {@link Publisher} to subscribe to. + * @param p5 The fifth upstream {@link Publisher} to subscribe to. + * @param p6 The sixth upstream {@link Publisher} to subscribe to. + * @param p7 The seventh upstream {@link Publisher} to subscribe to. + * @param type of the value from p1 + * @param type of the value from p2 + * @param type of the value from p3 + * @param type of the value from p4 + * @param type of the value from p5 + * @param type of the value from p6 + * @param type of the value from p7 + * + * @return a {@link Mono}. + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static Mono> zipDelayError(Mono p1, + Mono p2, + Mono p3, + Mono p4, + Mono p5, + Mono p6, + Mono p7) { + return onAssembly(new MonoZip(true, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5, p6, p7)); + } + + /** + * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal Monos} + * have produced an item, aggregating their values into a {@link Tuple8} and delaying errors. + * If a Mono source completes without value, all other sources are run to completion then + * the resulting {@link Mono} completes empty. + * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). + * + *

+ * + *

+ * @param p1 The first upstream {@link Publisher} to subscribe to. + * @param p2 The second upstream {@link Publisher} to subscribe to. + * @param p3 The third upstream {@link Publisher} to subscribe to. + * @param p4 The fourth upstream {@link Publisher} to subscribe to. + * @param p5 The fifth upstream {@link Publisher} to subscribe to. + * @param p6 The sixth upstream {@link Publisher} to subscribe to. + * @param p7 The seventh upstream {@link Publisher} to subscribe to. + * @param p8 The eight upstream {@link Publisher} to subscribe to. + * @param type of the value from p1 + * @param type of the value from p2 + * @param type of the value from p3 + * @param type of the value from p4 + * @param type of the value from p5 + * @param type of the value from p6 + * @param type of the value from p7 + * @param type of the value from p8 + * + * @return a {@link Mono}. + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static Mono> zipDelayError(Mono p1, + Mono p2, + Mono p3, + Mono p4, + Mono p5, + Mono p6, + Mono p7, + Mono p8) { + return onAssembly(new MonoZip(true, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5, p6, p7, p8)); + } + + /** + * Aggregate given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal + * Monos} have produced an item. Errors from the sources are delayed. + * If a Mono source completes without value, all other sources are run to completion then + * the resulting {@link Mono} completes empty. + * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). + *

+ * + *

+ * + * @param monos The monos to use. + * @param combinator the function to transform the combined array into an arbitrary + * object. + * @param the combined result + * + * @return a {@link Mono}. + */ + public static Mono zipDelayError(final Iterable> monos, Function combinator) { + return onAssembly(new MonoZip<>(true, combinator, monos)); + } + + /** + * Merge given monos into a new {@literal Mono} that will be fulfilled when all of the + * given {@literal Monos} have produced an item, aggregating their values according to + * the provided combinator function and delaying errors. + * If a Mono source completes without value, all other sources are run to completion then + * the resulting {@link Mono} completes empty. + * If several Monos error, their exceptions are combined (as suppressed exceptions on a root exception). + * + *

+ * + *

+ * @param monos The monos to use. + * @param combinator the function to transform the combined array into an arbitrary + * object. + * @param the combined result + * + * @return a combined {@link Mono}. + */ + public static Mono zipDelayError(Function + combinator, Mono... monos) { + if (monos.length == 0) { + return empty(); + } + if (monos.length == 1) { + return monos[0].map(d -> combinator.apply(new Object[]{d})); + } + return onAssembly(new MonoZip<>(true, combinator, monos)); + } + +// ============================================================================================================== +// Operators +// ============================================================================================================== + + /** + * Transform this {@link Mono} into a target type. + * + *

+	 * {@code mono.as(Flux::from).subscribe() }
+	 * 
+ * + * @param transformer the {@link Function} to immediately map this {@link Mono} + * into a target type + * @param

the returned instance type + * + * @return the {@link Mono} transformed to an instance of P + * @see #transformDeferred(Function) transformDeferred(Function) for a lazy transformation of Mono + */ + public final

P as(Function, P> transformer) { + return transformer.apply(this); + } + + /** + * Join the termination signals from this mono and another source into the returned + * void mono + * + *

+ * + *

+ * @param other the {@link Publisher} to wait for + * complete + * @return a new combined Mono + * @see #when + */ + public final Mono and(Publisher other) { + if (this instanceof MonoWhen) { + @SuppressWarnings("unchecked") MonoWhen o = (MonoWhen) this; + Mono result = o.whenAdditionalSource(other); + if (result != null) { + return result; + } + } + + return when(this, other); + } + + /** + * Subscribe to this {@link Mono} and block indefinitely until a next signal is + * received. Returns that value, or null if the Mono completes empty. In case the Mono + * errors, the original exception is thrown (wrapped in a {@link RuntimeException} if + * it was a checked exception). + * + *

+ * + *

+ * Note that each block() will trigger a new subscription: in other words, the result + * might miss signal from hot publishers. + * + * @return T the result + */ + @Nullable + public T block() { + BlockingMonoSubscriber subscriber = new BlockingMonoSubscriber<>(); + subscribe((Subscriber) subscriber); + return subscriber.blockingGet(); + } + + /** + * Subscribe to this {@link Mono} and block until a next signal is + * received or a timeout expires. Returns that value, or null if the Mono completes + * empty. In case the Mono errors, the original exception is thrown (wrapped in a + * {@link RuntimeException} if it was a checked exception). + * If the provided timeout expires, a {@link RuntimeException} is thrown. + * + *

+ * + *

+ * Note that each block() will trigger a new subscription: in other words, the result + * might miss signal from hot publishers. + * + * @param timeout maximum time period to wait for before raising a {@link RuntimeException} + * + * @return T the result + */ + @Nullable + public T block(Duration timeout) { + BlockingMonoSubscriber subscriber = new BlockingMonoSubscriber<>(); + subscribe((Subscriber) subscriber); + return subscriber.blockingGet(timeout.toNanos(), TimeUnit.NANOSECONDS); + } + + /** + * Subscribe to this {@link Mono} and block indefinitely until a next signal is + * received or the Mono completes empty. Returns an {@link Optional}, which can be used + * to replace the empty case with an Exception via {@link Optional#orElseThrow(Supplier)}. + * In case the Mono itself errors, the original exception is thrown (wrapped in a + * {@link RuntimeException} if it was a checked exception). + * + *

+ * + *

+ * Note that each blockOptional() will trigger a new subscription: in other words, the result + * might miss signal from hot publishers. + * + * @return T the result + */ + public Optional blockOptional() { + BlockingOptionalMonoSubscriber subscriber = new BlockingOptionalMonoSubscriber<>(); + subscribe((Subscriber) subscriber); + return subscriber.blockingGet(); + } + + /** + * Subscribe to this {@link Mono} and block until a next signal is + * received, the Mono completes empty or a timeout expires. Returns an {@link Optional} + * for the first two cases, which can be used to replace the empty case with an + * Exception via {@link Optional#orElseThrow(Supplier)}. + * In case the Mono itself errors, the original exception is thrown (wrapped in a + * {@link RuntimeException} if it was a checked exception). + * If the provided timeout expires, a {@link RuntimeException} is thrown. + * + *

+ * + *

+ * Note that each block() will trigger a new subscription: in other words, the result + * might miss signal from hot publishers. + * + * @param timeout maximum time period to wait for before raising a {@link RuntimeException} + * + * @return T the result + */ + public Optional blockOptional(Duration timeout) { + BlockingOptionalMonoSubscriber subscriber = new BlockingOptionalMonoSubscriber<>(); + subscribe((Subscriber) subscriber); + return subscriber.blockingGet(timeout.toNanos(), TimeUnit.NANOSECONDS); + } + + /** + * Cast the current {@link Mono} produced type into a target produced type. + * + *

+ * + * + * @param the {@link Mono} output type + * @param clazz the target type to cast to + * + * @return a casted {@link Mono} + */ + public final Mono cast(Class clazz) { + Objects.requireNonNull(clazz, "clazz"); + return map(clazz::cast); + } + + /** + * Turn this {@link Mono} into a hot source and cache last emitted signals for further {@link Subscriber}. + * Completion and Error will also be replayed. + *

+ * + *

+ * Once the first subscription is made to this {@link Mono}, the source is subscribed to and + * the signal will be cached, indefinitely. This process cannot be cancelled. + *

+ * In the face of multiple concurrent subscriptions, this operator ensures that only one + * subscription is made to the source. + * + * @return a replaying {@link Mono} + */ + public final Mono cache() { + return onAssembly(new MonoCacheTime<>(this)); + } + + /** + * Turn this {@link Mono} into a hot source and cache last emitted signals for further + * {@link Subscriber}, with an expiry timeout. + *

+ * Completion and Error will also be replayed until {@code ttl} triggers in which case + * the next {@link Subscriber} will start over a new subscription. + *

+ * + *

+ * Cache loading (ie. subscription to the source) is triggered atomically by the first + * subscription to an uninitialized or expired cache, which guarantees that a single + * cache load happens at a time (and other subscriptions will get notified of the newly + * cached value when it arrives). + * + * @return a replaying {@link Mono} + */ + public final Mono cache(Duration ttl) { + return cache(ttl, Schedulers.parallel()); + } + + /** + * Turn this {@link Mono} into a hot source and cache last emitted signals for further + * {@link Subscriber}, with an expiry timeout. + *

+ * Completion and Error will also be replayed until {@code ttl} triggers in which case + * the next {@link Subscriber} will start over a new subscription. + *

+ * + *

+ * Cache loading (ie. subscription to the source) is triggered atomically by the first + * subscription to an uninitialized or expired cache, which guarantees that a single + * cache load happens at a time (and other subscriptions will get notified of the newly + * cached value when it arrives). + * + * @param ttl Time-to-live for each cached item and post termination. + * @param timer the {@link Scheduler} on which to measure the duration. + * + * @return a replaying {@link Mono} + */ + public final Mono cache(Duration ttl, Scheduler timer) { + return onAssembly(new MonoCacheTime<>(this, ttl, timer)); + } + + /** + * Turn this {@link Mono} into a hot source and cache last emitted signal for further + * {@link Subscriber}, with an expiry timeout (TTL) that depends on said signal. + * A TTL of {@link Long#MAX_VALUE} milliseconds is interpreted as indefinite caching of + * the signal (no cache cleanup is scheduled, so the signal is retained as long as this + * {@link Mono} is not garbage collected). + *

+ * Empty completion and Error will also be replayed according to their respective TTL, + * so transient errors can be "retried" by letting the {@link Function} return + * {@link Duration#ZERO}. Such a transient exception would then be propagated to the first + * subscriber but the following subscribers would trigger a new source subscription. + *

+ * Exceptions in the TTL generators themselves are processed like the {@link Duration#ZERO} + * case, except the original signal is {@link Exceptions#addSuppressed(Throwable, Throwable) suppressed} + * (in case of onError) or {@link Hooks#onNextDropped(Consumer) dropped} + * (in case of onNext). + *

+ * Note that subscribers that come in perfectly simultaneously could receive the same + * cached signal even if the TTL is set to zero. + *

+ * Cache loading (ie. subscription to the source) is triggered atomically by the first + * subscription to an uninitialized or expired cache, which guarantees that a single + * cache load happens at a time (and other subscriptions will get notified of the newly + * cached value when it arrives). + * + * @param ttlForValue the TTL-generating {@link Function} invoked when source is valued + * @param ttlForError the TTL-generating {@link Function} invoked when source is erroring + * @param ttlForEmpty the TTL-generating {@link Supplier} invoked when source is empty + * @return a replaying {@link Mono} + */ + public final Mono cache(Function ttlForValue, + Function ttlForError, + Supplier ttlForEmpty) { + return cache(ttlForValue, ttlForError, ttlForEmpty, Schedulers.parallel()); + } + + /** + * Turn this {@link Mono} into a hot source and cache last emitted signal for further + * {@link Subscriber}, with an expiry timeout (TTL) that depends on said signal. + * A TTL of {@link Long#MAX_VALUE} milliseconds is interpreted as indefinite caching of + * the signal (no cache cleanup is scheduled, so the signal is retained as long as this + * {@link Mono} is not garbage collected). + *

+ * Empty completion and Error will also be replayed according to their respective TTL, + * so transient errors can be "retried" by letting the {@link Function} return + * {@link Duration#ZERO}. Such a transient exception would then be propagated to the first + * subscriber but the following subscribers would trigger a new source subscription. + *

+ * Exceptions in the TTL generators themselves are processed like the {@link Duration#ZERO} + * case, except the original signal is {@link Exceptions#addSuppressed(Throwable, Throwable) suppressed} + * (in case of onError) or {@link Hooks#onNextDropped(Consumer) dropped} + * (in case of onNext). + *

+ * Note that subscribers that come in perfectly simultaneously could receive the same + * cached signal even if the TTL is set to zero. + *

+ * Cache loading (ie. subscription to the source) is triggered atomically by the first + * subscription to an uninitialized or expired cache, which guarantees that a single + * cache load happens at a time (and other subscriptions will get notified of the newly + * cached value when it arrives). + * + * @param ttlForValue the TTL-generating {@link Function} invoked when source is valued + * @param ttlForError the TTL-generating {@link Function} invoked when source is erroring + * @param ttlForEmpty the TTL-generating {@link Supplier} invoked when source is empty + * @param timer the {@link Scheduler} on which to measure the duration. + * @return a replaying {@link Mono} + */ + public final Mono cache(Function ttlForValue, + Function ttlForError, + Supplier ttlForEmpty, + Scheduler timer) { + return onAssembly(new MonoCacheTime<>(this, ttlForValue, ttlForError, ttlForEmpty, timer)); + } + + /** + * Cache {@link Subscriber#onNext(Object) onNext} signal received from the source and replay it to other subscribers, + * while allowing invalidation by verifying the cached value against the given {@link Predicate} each time a late + * subscription occurs. + * Note that the {@link Predicate} is only evaluated if the cache is currently populated, ie. it is not applied + * upon receiving the source {@link Subscriber#onNext(Object) onNext} signal. + * For late subscribers, if the predicate returns {@code true} the cache is invalidated and a new subscription is made + * to the source in an effort to refresh the cache with a more up-to-date value to be passed to the new subscriber. + *

+ * The predicate is not strictly evaluated once per downstream subscriber. Rather, subscriptions happening in concurrent + * batches will trigger a single evaluation of the predicate. Similarly, a batch of subscriptions happening before + * the cache is populated (ie. before this operator receives an onNext signal after an invalidation) will always + * receive the incoming value without going through the {@link Predicate}. The predicate is only triggered by + * subscribers that come in AFTER the cache is populated. Therefore, it is possible that pre-population subscribers + * receive an "invalid" value, especially if the object can switch from a valid to an invalid state in a short amount + * of time (eg. between creation, cache population and propagation to the downstream subscriber(s)). + *

+ * If the cached value needs to be discarded in case of invalidation, the recommended way is to do so in the predicate + * directly. Note that some downstream subscribers might still be using or storing the value, for example if they + * haven't requested anything yet. + *

+ * As this form of caching is explicitly value-oriented, empty source completion signals and error signals are NOT + * cached. It is always possible to use {@link #materialize()} to cache these (further using {@link #filter(Predicate)} + * if one wants to only consider empty sources or error sources). + *

+ * Predicate is applied differently depending on whether the cache is populated or not: + *

    + *
  • IF EMPTY + *
    • first incoming subscriber creates a new COORDINATOR and adds itself
    + *
  • + *
  • IF COORDINATOR + *
      + *
    1. each incoming subscriber is added to the current "batch" (COORDINATOR)
    2. + *
    3. once the value is received, the predicate is applied ONCE + *
        + *
      1. mismatch: all the batch is terminated with an error + * -> we're back to init state, next subscriber will trigger a new coordinator and a new subscription
      2. + *
      3. ok: all the batch is completed with the value -> cache is now POPULATED
      4. + *
      + *
    4. + *
    + *
  • + *
  • IF POPULATED + *
      + *
    1. each incoming subscriber causes the predicate to apply
    2. + *
    3. if ok: complete that subscriber with the value
    4. + *
    5. if mismatch, swap the current POPULATED with a new COORDINATOR and add the subscriber to that coordinator
    6. + *
    7. imagining a race between sub1 and sub2: + *
        + *
      1. OK NOK will naturally lead to sub1 completing and sub2 being put on wait inside a new COORDINATOR
      2. + *
      3. NOK NOK will race swap of POPULATED with COORDINATOR1 and COORDINATOR2 respectively + *
          + *
        1. if sub1 swaps, sub2 will dismiss the COORDINATOR2 it failed to swap and loop back, see COORDINATOR1 and add itself
        2. + *
        3. if sub2 swaps, the reverse happens
        4. + *
        5. if value is populated in the time it takes for sub2 to loop back, sub2 sees a value and triggers the predicate again (hopefully passing)
        6. + *
        + *
      4. + *
      + *
    8. + *
    + *
  • + *
+ *

+ * Cancellation is only possible for downstream subscribers when they've been added to a COORDINATOR. + * Subscribers that are received when POPULATED will either be completed right away or (if the predicate fails) end up being added to a COORDINATOR. + *

+ * When cancelling a COORDINATOR-issued subscription: + *

    + *
  1. removes itself from batch
  2. + *
  3. if 0 subscribers remaining + *
      + *
    1. swap COORDINATOR with EMPTY
    2. + *
    3. COORDINATOR cancels its source
    4. + *
    + *
  4. + *
+ *

+ * The fact that COORDINATOR cancels its source when no more subscribers remain is important, because it prevents issues with a never() source + * or a source that never produces a value passing the predicate (assuming timeouts on the subscriber). + * + * @param invalidationPredicate the {@link Predicate} used for cache invalidation. Returning {@code true} means the value is invalid and should be + * removed from the cache. + * @return a new cached {@link Mono} which can be invalidated + */ + public final Mono cacheInvalidateIf(Predicate invalidationPredicate) { + return onAssembly(new MonoCacheInvalidateIf<>(this, invalidationPredicate)); + } + + /** + * Cache {@link Subscriber#onNext(Object) onNext} signal received from the source and replay it to other subscribers, + * while allowing invalidation via a {@link Mono Mono<Void>} companion trigger generated from the currently + * cached value. + *

+ * As this form of caching is explicitly value-oriented, empty source completion signals and error signals are NOT + * cached. It is always possible to use {@link #materialize()} to cache these (further using {@link #filter(Predicate)} + * if one wants to only consider empty sources or error sources). The exception is still propagated to the subscribers + * that have accumulated between the time the source has been subscribed to and the time the onError/onComplete terminal + * signal is received. An empty source is turned into a {@link NoSuchElementException} onError. + *

+ * Completion of the trigger will invalidate the cached element, so the next subscriber that comes in will trigger + * a new subscription to the source, re-populating the cache and re-creating a new trigger out of that value. + *

+ *

    + *
  • + * If the trigger completes with an error, all registered subscribers are terminated with the same error. + *
  • + *
  • + * If all the subscribers are cancelled before the cache is populated (ie. an attempt to + * cache a {@link Mono#never()}), the source subscription is cancelled. + *
  • + *
  • + * Cancelling a downstream subscriber once the cache has been populated is not necessarily relevant, + * as the value will be immediately replayed on subscription, which usually means within onSubscribe (so + * earlier than any cancellation can happen). That said the operator will make best efforts to detect such + * cancellations and avoid propagating the value to these subscribers. + *
  • + *
+ *

+ * If the cached value needs to be discarded in case of invalidation, use the {@link #cacheInvalidateWhen(Function, Consumer)} version. + * Note that some downstream subscribers might still be using or storing the value, for example if they + * haven't requested anything yet. + *

+ * Trigger is generated only after a subscribers in the COORDINATOR have received the value, and only once. + * The only way to get out of the POPULATED state is to use the trigger, so there cannot be multiple trigger subscriptions, nor concurrent triggering. + *

+ * Cancellation is only possible for downstream subscribers when they've been added to a COORDINATOR. + * Subscribers that are received when POPULATED will either be completed right away or (if the predicate fails) end up being added to a COORDINATOR. + *

+ * When cancelling a COORDINATOR-issued subscription: + *

    + *
  1. removes itself from batch
  2. + *
  3. if 0 subscribers remaining + *
      + *
    1. swap COORDINATOR with EMPTY
    2. + *
    3. COORDINATOR cancels its source
    4. + *
    + *
  4. + *
+ *

+ * The fact that COORDINATOR cancels its source when no more subscribers remain is important, because it prevents issues with a never() source + * or a source that never produces a value passing the predicate (assuming timeouts on the subscriber). + * + * @param invalidationTriggerGenerator the {@link Function} that generates new {@link Mono Mono<Void>} triggers + * used for invalidation + * @return a new cached {@link Mono} which can be invalidated + */ + public final Mono cacheInvalidateWhen(Function> invalidationTriggerGenerator) { + return onAssembly(new MonoCacheInvalidateWhen<>(this, invalidationTriggerGenerator, null)); + } + + /** + * Cache {@link Subscriber#onNext(Object) onNext} signal received from the source and replay it to other subscribers, + * while allowing invalidation via a {@link Mono Mono<Void>} companion trigger generated from the currently + * cached value. + *

+ * As this form of caching is explicitly value-oriented, empty source completion signals and error signals are NOT + * cached. It is always possible to use {@link #materialize()} to cache these (further using {@link #filter(Predicate)} + * if one wants to only consider empty sources or error sources). The exception is still propagated to the subscribers + * that have accumulated between the time the source has been subscribed to and the time the onError/onComplete terminal + * signal is received. An empty source is turned into a {@link NoSuchElementException} onError. + *

+ * Completion of the trigger will invalidate the cached element, so the next subscriber that comes in will trigger + * a new subscription to the source, re-populating the cache and re-creating a new trigger out of that value. + *

+ *

    + *
  • + * If the trigger completes with an error, all registered subscribers are terminated with the same error. + *
  • + *
  • + * If all the subscribers are cancelled before the cache is populated (ie. an attempt to + * cache a {@link Mono#never()}), the source subscription is cancelled. + *
  • + *
  • + * Cancelling a downstream subscriber once the cache has been populated is not necessarily relevant, + * as the value will be immediately replayed on subscription, which usually means within onSubscribe (so + * earlier than any cancellation can happen). That said the operator will make best efforts to detect such + * cancellations and avoid propagating the value to these subscribers. + *
  • + *
+ *

+ * Once a cached value is invalidated, it is passed to the provided {@link Consumer} (which MUST complete normally). + * Note that some downstream subscribers might still be using or storing the value, for example if they + * haven't requested anything yet. + *

+ * Trigger is generated only after a subscribers in the COORDINATOR have received the value, and only once. + * The only way to get out of the POPULATED state is to use the trigger, so there cannot be multiple trigger subscriptions, nor concurrent triggering. + *

+ * Cancellation is only possible for downstream subscribers when they've been added to a COORDINATOR. + * Subscribers that are received when POPULATED will either be completed right away or (if the predicate fails) end up being added to a COORDINATOR. + *

+ * When cancelling a COORDINATOR-issued subscription: + *

    + *
  1. removes itself from batch
  2. + *
  3. if 0 subscribers remaining + *
      + *
    1. swap COORDINATOR with EMPTY
    2. + *
    3. COORDINATOR cancels its source
    4. + *
    + *
  4. + *
+ *

+ * The fact that COORDINATOR cancels its source when no more subscribers remain is important, because it prevents issues with a never() source + * or a source that never produces a value passing the predicate (assuming timeouts on the subscriber). + * + * @param invalidationTriggerGenerator the {@link Function} that generates new {@link Mono Mono<Void>} triggers + * used for invalidation + * @param onInvalidate the {@link Consumer} that will be applied to cached value upon invalidation + * @return a new cached {@link Mono} which can be invalidated + */ + public final Mono cacheInvalidateWhen(Function> invalidationTriggerGenerator, + Consumer onInvalidate) { + return onAssembly(new MonoCacheInvalidateWhen<>(this, invalidationTriggerGenerator, onInvalidate)); + } + + /** + * Prepare this {@link Mono} so that subscribers will cancel from it on a + * specified + * {@link Scheduler}. + * + *

+ * + * + * @param scheduler the {@link Scheduler} to signal cancel on + * + * @return a scheduled cancel {@link Mono} + */ + public final Mono cancelOn(Scheduler scheduler) { + return onAssembly(new MonoCancelOn<>(this, scheduler)); + } + + /** + * Activate traceback (full assembly tracing) for this particular {@link Mono}, in case of an error + * upstream of the checkpoint. Tracing incurs the cost of an exception stack trace + * creation. + *

+ * It should be placed towards the end of the reactive chain, as errors + * triggered downstream of it cannot be observed and augmented with assembly trace. + *

+ * The traceback is attached to the error as a {@link Throwable#getSuppressed() suppressed exception}. + * As such, if the error is a {@link Exceptions#isMultiple(Throwable) composite one}, the traceback + * would appear as a component of the composite. In any case, the traceback nature can be detected via + * {@link Exceptions#isTraceback(Throwable)}. + * + * @return the assembly tracing {@link Mono} + */ + public final Mono checkpoint() { + return checkpoint(null, true); + } + + /** + * Activate traceback (assembly marker) for this particular {@link Mono} by giving it a description that + * will be reflected in the assembly traceback in case of an error upstream of the + * checkpoint. Note that unlike {@link #checkpoint()}, this doesn't create a + * filled stack trace, avoiding the main cost of the operator. + * However, as a trade-off the description must be unique enough for the user to find + * out where this Mono was assembled. If you only want a generic description, and + * still rely on the stack trace to find the assembly site, use the + * {@link #checkpoint(String, boolean)} variant. + *

+ * It should be placed towards the end of the reactive chain, as errors + * triggered downstream of it cannot be observed and augmented with assembly trace. + *

+ * The traceback is attached to the error as a {@link Throwable#getSuppressed() suppressed exception}. + * As such, if the error is a {@link Exceptions#isMultiple(Throwable) composite one}, the traceback + * would appear as a component of the composite. In any case, the traceback nature can be detected via + * {@link Exceptions#isTraceback(Throwable)}. + * + * @param description a unique enough description to include in the light assembly traceback. + * @return the assembly marked {@link Mono} + */ + public final Mono checkpoint(String description) { + return checkpoint(Objects.requireNonNull(description), false); + } + + /** + * Activate traceback (full assembly tracing or the lighter assembly marking depending on the + * {@code forceStackTrace} option). + *

+ * By setting the {@code forceStackTrace} parameter to {@literal true}, activate assembly + * tracing for this particular {@link Mono} and give it a description that + * will be reflected in the assembly traceback in case of an error upstream of the + * checkpoint. Note that unlike {@link #checkpoint(String)}, this will incur + * the cost of an exception stack trace creation. The description could for + * example be a meaningful name for the assembled mono or a wider correlation ID, + * since the stack trace will always provide enough information to locate where this + * Flux was assembled. + *

+ * By setting {@code forceStackTrace} to {@literal false}, behaves like + * {@link #checkpoint(String)} and is subject to the same caveat in choosing the + * description. + *

+ * It should be placed towards the end of the reactive chain, as errors + * triggered downstream of it cannot be observed and augmented with assembly marker. + *

+ * The traceback is attached to the error as a {@link Throwable#getSuppressed() suppressed exception}. + * As such, if the error is a {@link Exceptions#isMultiple(Throwable) composite one}, the traceback + * would appear as a component of the composite. In any case, the traceback nature can be detected via + * {@link Exceptions#isTraceback(Throwable)}. + * + * @param description a description (must be unique enough if forceStackTrace is set + * to false). + * @param forceStackTrace false to make a light checkpoint without a stacktrace, true + * to use a stack trace. + * @return the assembly marked {@link Mono}. + */ + public final Mono checkpoint(@Nullable String description, boolean forceStackTrace) { + final AssemblySnapshot stacktrace; + if (!forceStackTrace) { + stacktrace = new CheckpointLightSnapshot(description); + } + else { + stacktrace = new CheckpointHeavySnapshot(description, Traces.callSiteSupplierFactory.get()); + } + + return new MonoOnAssembly<>(this, stacktrace); + } + + /** + * Concatenate emissions of this {@link Mono} with the provided {@link Publisher} + * (no interleave). + *

+ * + * + * @param other the {@link Publisher} sequence to concat after this {@link Flux} + * + * @return a concatenated {@link Flux} + */ + public final Flux concatWith(Publisher other) { + return Flux.concat(this, other); + } + + /** + * If context-propagation library + * is on the classpath, this is a convenience shortcut to capture thread local values during the + * subscription phase and put them in the {@link Context} that is visible upstream of this operator. + *

+ * As a result this operator should generally be used as close as possible to the end of + * the chain / subscription point. + *

+ * If the {@link ContextView} visible upstream is not empty, a small subset of operators will automatically + * restore the context snapshot ({@link #handle(BiConsumer) handle}, {@link #tap(SignalListenerFactory) tap}). + * If context-propagation is not available at runtime, this operator simply returns the current {@link Mono} + * instance. + * + * @return a new {@link Flux} where context-propagation API has been used to capture entries and + * inject them into the {@link Context} + * @see #handle(BiConsumer) + * @see #tap(SignalListenerFactory) + */ + public final Mono contextCapture() { + if (!ContextPropagation.isContextPropagationAvailable()) { + return this; + } + return onAssembly(new MonoContextWrite<>(this, ContextPropagation.contextCapture())); + } + + /** + * Enrich the {@link Context} visible from downstream for the benefit of upstream + * operators, by making all values from the provided {@link ContextView} visible on top + * of pairs from downstream. + *

+ * A {@link Context} (and its {@link ContextView}) is tied to a given subscription + * and is read by querying the downstream {@link Subscriber}. {@link Subscriber} that + * don't enrich the context instead access their own downstream's context. As a result, + * this operator conceptually enriches a {@link Context} coming from under it in the chain + * (downstream, by default an empty one) and makes the new enriched {@link Context} + * visible to operators above it in the chain. + * + * @param contextToAppend the {@link ContextView} to merge with the downstream {@link Context}, + * resulting in a new more complete {@link Context} that will be visible from upstream. + * + * @return a contextualized {@link Mono} + * @see ContextView + */ + public final Mono contextWrite(ContextView contextToAppend) { + return contextWrite(c -> c.putAll(contextToAppend)); + } + + /** + * Enrich the {@link Context} visible from downstream for the benefit of upstream + * operators, by applying a {@link Function} to the downstream {@link Context}. + *

+ * The {@link Function} takes a {@link Context} for convenience, allowing to easily + * call {@link Context#put(Object, Object) write APIs} to return a new {@link Context}. + *

+ * A {@link Context} (and its {@link ContextView}) is tied to a given subscription + * and is read by querying the downstream {@link Subscriber}. {@link Subscriber} that + * don't enrich the context instead access their own downstream's context. As a result, + * this operator conceptually enriches a {@link Context} coming from under it in the chain + * (downstream, by default an empty one) and makes the new enriched {@link Context} + * visible to operators above it in the chain. + * + * @param contextModifier the {@link Function} to apply to the downstream {@link Context}, + * resulting in a new more complete {@link Context} that will be visible from upstream. + * + * @return a contextualized {@link Mono} + * @see Context + */ + public final Mono contextWrite(Function contextModifier) { + return onAssembly(new MonoContextWrite<>(this, contextModifier)); + } + + /** + * Provide a default single value if this mono is completed without any data + * + *

+ * + *

+ * @param defaultV the alternate value if this sequence is empty + * + * @return a new {@link Mono} + * + * @see Flux#defaultIfEmpty(Object) + */ + public final Mono defaultIfEmpty(T defaultV) { + if (this instanceof Fuseable.ScalarCallable) { + try { + T v = block(); + if (v == null) { + return Mono.just(defaultV); + } + } + catch (Throwable e) { + //leave MonoError returns as this + } + return this; + } + return onAssembly(new MonoDefaultIfEmpty<>(this, defaultV)); + } + + /** + * Delay this {@link Mono} element ({@link Subscriber#onNext} signal) by a given + * duration. Empty Monos or error signals are not delayed. + * + *

+ * + * + *

+ * Note that the scheduler on which the Mono chain continues execution will be the + * {@link Schedulers#parallel() parallel} scheduler if the mono is valued, or the + * current scheduler if the mono completes empty or errors. + * + * @param delay duration by which to delay the {@link Subscriber#onNext} signal + * @return a delayed {@link Mono} + */ + public final Mono delayElement(Duration delay) { + return delayElement(delay, Schedulers.parallel()); + } + + /** + * Delay this {@link Mono} element ({@link Subscriber#onNext} signal) by a given + * {@link Duration}, on a particular {@link Scheduler}. Empty monos or error signals are not delayed. + * + *

+ * + * + *

+ * Note that the scheduler on which the mono chain continues execution will be the + * scheduler provided if the mono is valued, or the current scheduler if the mono + * completes empty or errors. + * + * @param delay {@link Duration} by which to delay the {@link Subscriber#onNext} signal + * @param timer a time-capable {@link Scheduler} instance to delay the value signal on + * @return a delayed {@link Mono} + */ + public final Mono delayElement(Duration delay, Scheduler timer) { + return onAssembly(new MonoDelayElement<>(this, delay.toNanos(), TimeUnit.NANOSECONDS, timer)); + } + + /** + * Subscribe to this {@link Mono} and another {@link Publisher} that is generated from + * this Mono's element and which will be used as a trigger for relaying said element. + *

+ * That is to say, the resulting {@link Mono} delays until this Mono's element is + * emitted, generates a trigger Publisher and then delays again until the trigger + * Publisher terminates. + *

+ * Note that contiguous calls to all delayUntil are fused together. + * The triggers are generated and subscribed to in sequence, once the previous trigger + * completes. Error is propagated immediately + * downstream. In both cases, an error in the source is immediately propagated. + *

+ * + * + * @param triggerProvider a {@link Function} that maps this Mono's value into a + * {@link Publisher} whose termination will trigger relaying the value. + * + * @return this Mono, but delayed until the derived publisher terminates. + */ + public final Mono delayUntil(Function> triggerProvider) { + Objects.requireNonNull(triggerProvider, "triggerProvider required"); + if (this instanceof MonoDelayUntil) { + return ((MonoDelayUntil) this).copyWithNewTriggerGenerator(false,triggerProvider); + } + return onAssembly(new MonoDelayUntil<>(this, triggerProvider)); + } + + /** + * Delay the {@link Mono#subscribe(Subscriber) subscription} to this {@link Mono} source until the given + * period elapses. + * + *

+ * + * + * @param delay duration before subscribing this {@link Mono} + * + * @return a delayed {@link Mono} + * + */ + public final Mono delaySubscription(Duration delay) { + return delaySubscription(delay, Schedulers.parallel()); + } + + /** + * Delay the {@link Mono#subscribe(Subscriber) subscription} to this {@link Mono} source until the given + * {@link Duration} elapses. + * + *

+ * + * + * @param delay {@link Duration} before subscribing this {@link Mono} + * @param timer a time-capable {@link Scheduler} instance to run on + * + * @return a delayed {@link Mono} + * + */ + public final Mono delaySubscription(Duration delay, Scheduler timer) { + return delaySubscription(Mono.delay(delay, timer)); + } + + /** + * Delay the subscription to this {@link Mono} until another {@link Publisher} + * signals a value or completes. + * + *

+ * + * + * @param subscriptionDelay a + * {@link Publisher} to signal by next or complete this {@link Mono#subscribe(Subscriber)} + * @param the other source type + * + * @return a delayed {@link Mono} + * + */ + public final Mono delaySubscription(Publisher subscriptionDelay) { + return onAssembly(new MonoDelaySubscription<>(this, subscriptionDelay)); + } + + /** + * An operator working only if this {@link Mono} emits onNext, onError or onComplete {@link Signal} + * instances, transforming these {@link #materialize() materialized} signals into + * real signals on the {@link Subscriber}. + * The error {@link Signal} will trigger onError and complete {@link Signal} will trigger + * onComplete. + * + *

+ * + * + * @param the dematerialized type + * @return a dematerialized {@link Mono} + * @see #materialize() + */ + public final Mono dematerialize() { + @SuppressWarnings("unchecked") + Mono> thiz = (Mono>) this; + return onAssembly(new MonoDematerialize<>(thiz)); + } + + /** + * Add behavior (side-effect) triggered after the {@link Mono} terminates, either by + * completing downstream successfully or with an error. + *

+ * + *

+ * The relevant signal is propagated downstream, then the {@link Runnable} is executed. + * + * @param afterTerminate the callback to call after {@link Subscriber#onComplete} or {@link Subscriber#onError} + * + * @return an observed {@link Mono} + */ + public final Mono doAfterTerminate(Runnable afterTerminate) { + Objects.requireNonNull(afterTerminate, "afterTerminate"); + return onAssembly(new MonoPeekTerminal<>(this, null, null, (s, e) -> afterTerminate.run())); + } + + /** + * Add behavior (side-effect) triggered before the {@link Mono} is + * subscribed to, which should be the first event after assembly time. + *

+ * + *

+ * Note that when several {@link #doFirst(Runnable)} operators are used anywhere in a + * chain of operators, their order of execution is reversed compared to the declaration + * order (as subscribe signal flows backward, from the ultimate subscriber to the source + * publisher): + *


+	 * Mono.just(1v)
+	 *     .doFirst(() -> System.out.println("three"))
+	 *     .doFirst(() -> System.out.println("two"))
+	 *     .doFirst(() -> System.out.println("one"));
+	 * //would print one two three
+	 * 
+	 * 
+ *

+ * In case the {@link Runnable} throws an exception, said exception will be directly + * propagated to the subscribing {@link Subscriber} along with a no-op {@link Subscription}, + * similarly to what {@link #error(Throwable)} does. Otherwise, after the handler has + * executed, the {@link Subscriber} is directly subscribed to the original source + * {@link Mono} ({@code this}). + *

+ * This side-effect method provides stronger first guarantees compared to + * {@link #doOnSubscribe(Consumer)}, which is triggered once the {@link Subscription} + * has been set up and passed to the {@link Subscriber}. + * + * @param onFirst the callback to execute before the {@link Mono} is subscribed to + * @return an observed {@link Mono} + */ + public final Mono doFirst(Runnable onFirst) { + Objects.requireNonNull(onFirst, "onFirst"); + if (this instanceof Fuseable) { + return onAssembly(new MonoDoFirstFuseable<>(this, onFirst)); + } + return onAssembly(new MonoDoFirst<>(this, onFirst)); + } + + /** + * Add behavior triggering after the {@link Mono} terminates for any reason, + * including cancellation. The terminating event ({@link SignalType#ON_COMPLETE}, + * {@link SignalType#ON_ERROR} and {@link SignalType#CANCEL}) is passed to the consumer, + * which is executed after the signal has been passed downstream. + *

+ * Note that the fact that the signal is propagated downstream before the callback is + * executed means that several doFinally in a row will be executed in + * reverse order. If you want to assert the execution of the callback + * please keep in mind that the Mono will complete before it is executed, so its + * effect might not be visible immediately after eg. a {@link #block()}. + *

+ * + * + * + * @param onFinally the callback to execute after a terminal signal (complete, error + * or cancel) + * @return an observed {@link Mono} + */ + public final Mono doFinally(Consumer onFinally) { + Objects.requireNonNull(onFinally, "onFinally"); + return onAssembly(new MonoDoFinally<>(this, onFinally)); + } + + /** + * Add behavior triggered when the {@link Mono} is cancelled. + *

+ * + *

+ * The handler is executed first, then the cancel signal is propagated upstream + * to the source. + * + * @param onCancel the callback to call on {@link Subscription#cancel()} + * + * @return a new {@link Mono} + */ + public final Mono doOnCancel(Runnable onCancel) { + Objects.requireNonNull(onCancel, "onCancel"); + return doOnSignal(this, null, null, null, onCancel); + } + + /** + * Potentially modify the behavior of the whole chain of operators upstream of this one to + * conditionally clean up elements that get discarded by these operators. + *

+ * The {@code discardHook} MUST be idempotent and safe to use on any instance of the desired + * type. + * Calls to this method are additive, and the order of invocation of the {@code discardHook} + * is the same as the order of declaration (calling {@code .filter(...).doOnDiscard(first).doOnDiscard(second)} + * will let the filter invoke {@code first} then {@code second} handlers). + *

+ * Two main categories of discarding operators exist: + *

    + *
  • filtering operators, dropping some source elements as part of their designed behavior
  • + *
  • operators that prefetch a few elements and keep them around pending a request, but get cancelled/in error
  • + *
+ * WARNING: Not all operators support this instruction. The ones that do are identified in the javadoc by + * the presence of a Discard Support section. + * + * @param type the {@link Class} of elements in the upstream chain of operators that + * this cleanup hook should take into account. + * @param discardHook a {@link Consumer} of elements in the upstream chain of operators + * that performs the cleanup. + * @return a {@link Mono} that cleans up matching elements that get discarded upstream of it. + */ + public final Mono doOnDiscard(final Class type, final Consumer discardHook) { + return contextWrite(Operators.discardLocalAdapter(type, discardHook)); + } + + /** + * Add behavior triggered when the {@link Mono} emits a data successfully. + * + *

+ * + *

+ * The {@link Consumer} is executed first, then the onNext signal is propagated + * downstream. + * + * @param onNext the callback to call on {@link Subscriber#onNext} + * + * @return a new {@link Mono} + */ + public final Mono doOnNext(Consumer onNext) { + Objects.requireNonNull(onNext, "onNext"); + return doOnSignal(this, null, onNext, null, null); + } + + /** + * Add behavior triggered as soon as the {@link Mono} can be considered to have completed successfully. + * The value passed to the {@link Consumer} reflects the type of completion: + * + *

    + *
  • null : completed without data. handler is executed right before onComplete is propagated downstream
  • + *
  • T: completed with data. handler is executed right before onNext is propagated downstream
  • + *
+ * + *

+ * + *

+ * The {@link Consumer} is executed before propagating either onNext or onComplete downstream. + * + * @param onSuccess the callback to call on, argument is null if the {@link Mono} + * completes without data + * {@link Subscriber#onNext} or {@link Subscriber#onComplete} without preceding {@link Subscriber#onNext} + * + * @return a new {@link Mono} + */ + public final Mono doOnSuccess(Consumer onSuccess) { + Objects.requireNonNull(onSuccess, "onSuccess"); + return doOnTerminalSignal(this, onSuccess, null, null); + } + + /** + * Add behavior triggered when the {@link Mono} emits an item, fails with an error + * or completes successfully. All these events are represented as a {@link Signal} + * that is passed to the side-effect callback. Note that this is an advanced operator, + * typically used for monitoring of a Mono. + * These {@link Signal} have a {@link Context} associated to them. + *

+ * + *

+ * The {@link Consumer} is executed first, then the relevant signal is propagated + * downstream. + * + * @param signalConsumer the mandatory callback to call on + * {@link Subscriber#onNext(Object)}, {@link Subscriber#onError(Throwable)} and + * {@link Subscriber#onComplete()} + * @return an observed {@link Mono} + * @see #doOnNext(Consumer) + * @see #doOnError(Consumer) + * @see #materialize() + * @see Signal + */ + public final Mono doOnEach(Consumer> signalConsumer) { + Objects.requireNonNull(signalConsumer, "signalConsumer"); + if (this instanceof Fuseable) { + return onAssembly(new MonoDoOnEachFuseable<>(this, signalConsumer)); + } + return onAssembly(new MonoDoOnEach<>(this, signalConsumer)); + + } + + /** + * Add behavior triggered when the {@link Mono} completes with an error. + * + *

+ * + *

+ * The {@link Consumer} is executed first, then the onError signal is propagated + * downstream. + * + * @param onError the error callback to call on {@link Subscriber#onError(Throwable)} + * + * @return a new {@link Mono} + */ + public final Mono doOnError(Consumer onError) { + Objects.requireNonNull(onError, "onError"); + return doOnTerminalSignal(this, null, onError, null); + } + + + /** + * Add behavior triggered when the {@link Mono} completes with an error matching the given exception type. + *

+ * + *

+ * The {@link Consumer} is executed first, then the onError signal is propagated + * downstream. + * + * @param exceptionType the type of exceptions to handle + * @param onError the error handler for relevant errors + * @param type of the error to handle + * + * @return an observed {@link Mono} + * + */ + public final Mono doOnError(Class exceptionType, + final Consumer onError) { + Objects.requireNonNull(exceptionType, "type"); + Objects.requireNonNull(onError, "onError"); + return doOnTerminalSignal(this, null, + error -> { + if (exceptionType.isInstance(error)) onError.accept(exceptionType.cast(error)); + }, + null); + } + + /** + * Add behavior triggered when the {@link Mono} completes with an error matching the given predicate. + *

+ * + *

+ * The {@link Consumer} is executed first, then the onError signal is propagated + * downstream. + * + * @param predicate the matcher for exceptions to handle + * @param onError the error handler for relevant error + * + * @return an observed {@link Mono} + * + */ + public final Mono doOnError(Predicate predicate, + final Consumer onError) { + Objects.requireNonNull(predicate, "predicate"); + Objects.requireNonNull(onError, "onError"); + return doOnTerminalSignal(this, null, + error -> { + if (predicate.test(error)) onError.accept(error); + }, + null); + } + /** + * Add behavior triggering a {@link LongConsumer} when the {@link Mono} receives any request. + *

+ * Note that non fatal error raised in the callback will not be propagated and + * will simply trigger {@link Operators#onOperatorError(Throwable, Context)}. + * + *

+ * + *

+ * The {@link LongConsumer} is executed first, then the request signal is propagated + * upstream to the parent. + * + * @param consumer the consumer to invoke on each request + * + * @return an observed {@link Mono} + */ + public final Mono doOnRequest(final LongConsumer consumer) { + Objects.requireNonNull(consumer, "consumer"); + return doOnSignal(this, null, null, consumer, null); + } + + /** + * Add behavior (side-effect) triggered when the {@link Mono} is being subscribed, + * that is to say when a {@link Subscription} has been produced by the {@link Publisher} + * and is being passed to the {@link Subscriber#onSubscribe(Subscription)}. + *

+ * This method is not intended for capturing the subscription and calling its methods, + * but for side effects like monitoring. For instance, the correct way to cancel a subscription is + * to call {@link Disposable#dispose()} on the Disposable returned by {@link Mono#subscribe()}. + *

+ * + *

+ * The {@link Consumer} is executed first, then the {@link Subscription} is propagated + * downstream to the next subscriber in the chain that is being established. + * + * @param onSubscribe the callback to call on {@link Subscriber#onSubscribe(Subscription)} + * + * @return a new {@link Mono} + * @see #doFirst(Runnable) + */ + public final Mono doOnSubscribe(Consumer onSubscribe) { + Objects.requireNonNull(onSubscribe, "onSubscribe"); + return doOnSignal(this, onSubscribe, null, null, null); + } + + /** + * Add behavior triggered when the {@link Mono} terminates, either by completing with a value, + * completing empty or failing with an error. Unlike in {@link Flux#doOnTerminate(Runnable)}, + * the simple fact that a {@link Mono} emits {@link Subscriber#onNext(Object) onNext} implies + * completion, so the handler is invoked BEFORE the element is propagated (same as with {@link #doOnSuccess(Consumer)}). + * + *

+ *

+ * The {@link Runnable} is executed first, then the onNext/onComplete/onError signal is propagated + * downstream. + * + * @param onTerminate the callback to call {@link Subscriber#onNext}, {@link Subscriber#onComplete} without preceding {@link Subscriber#onNext} or {@link Subscriber#onError} + * + * @return a new {@link Mono} + */ + public final Mono doOnTerminate(Runnable onTerminate) { + Objects.requireNonNull(onTerminate, "onTerminate"); + return doOnTerminalSignal(this, ignoreValue -> onTerminate.run(), ignoreError -> onTerminate.run(), null); + } + + /** + * Map this {@link Mono} into {@link reactor.util.function.Tuple2 Tuple2<Long, T>} + * of timemillis and source data. The timemillis corresponds to the elapsed time between + * the subscribe and the first next signal, as measured by the {@link Schedulers#parallel() parallel} scheduler. + * + *

+ * + * + * @return a new {@link Mono} that emits a tuple of time elapsed in milliseconds and matching data + * @see #timed() + */ + public final Mono> elapsed() { + return elapsed(Schedulers.parallel()); + } + + /** + * Map this {@link Mono} sequence into {@link reactor.util.function.Tuple2 Tuple2<Long, T>} + * of timemillis and source data. The timemillis corresponds to the elapsed time between the subscribe and the first + * next signal, as measured by the provided {@link Scheduler}. + * + *

+ * + * + * @param scheduler a {@link Scheduler} instance to read time from + * @return a new {@link Mono} that emits a tuple of time elapsed in milliseconds and matching data + * @see #timed(Scheduler) + */ + public final Mono> elapsed(Scheduler scheduler) { + Objects.requireNonNull(scheduler, "scheduler"); + return onAssembly(new MonoElapsed<>(this, scheduler)); + } + + /** + * Recursively expand elements into a graph and emit all the resulting element, + * in a depth-first traversal order. + *

+ * That is: emit the value from this {@link Mono}, expand it and emit the first value + * at this first level of recursion, and so on... When no more recursion is possible, + * backtrack to the previous level and re-apply the strategy. + *

+ * For example, given the hierarchical structure + *

+	 *  A
+	 *   - AA
+	 *     - aa1
+	 *   - AB
+	 *     - ab1
+	 *   - a1
+	 * 
+ * + * Expands {@code Mono.just(A)} into + *
+	 *  A
+	 *  AA
+	 *  aa1
+	 *  AB
+	 *  ab1
+	 *  a1
+	 * 
+ * + * @param expander the {@link Function} applied at each level of recursion to expand + * values into a {@link Publisher}, producing a graph. + * @param capacityHint a capacity hint to prepare the inner queues to accommodate n + * elements per level of recursion. + * + * @return this Mono expanded depth-first to a {@link Flux} + */ + public final Flux expandDeep(Function> expander, + int capacityHint) { + return Flux.onAssembly(new MonoExpand<>(this, expander, false, capacityHint)); + } + + /** + * Recursively expand elements into a graph and emit all the resulting element, + * in a depth-first traversal order. + *

+ * That is: emit the value from this {@link Mono}, expand it and emit the first value + * at this first level of recursion, and so on... When no more recursion is possible, + * backtrack to the previous level and re-apply the strategy. + *

+ * For example, given the hierarchical structure + *

+	 *  A
+	 *   - AA
+	 *     - aa1
+	 *   - AB
+	 *     - ab1
+	 *   - a1
+	 * 
+ * + * Expands {@code Mono.just(A)} into + *
+	 *  A
+	 *  AA
+	 *  aa1
+	 *  AB
+	 *  ab1
+	 *  a1
+	 * 
+ * + * @param expander the {@link Function} applied at each level of recursion to expand + * values into a {@link Publisher}, producing a graph. + * + * @return this Mono expanded depth-first to a {@link Flux} + */ + public final Flux expandDeep(Function> expander) { + return expandDeep(expander, Queues.SMALL_BUFFER_SIZE); + } + + /** + * Recursively expand elements into a graph and emit all the resulting element using + * a breadth-first traversal strategy. + *

+ * That is: emit the value from this {@link Mono} first, then expand it at a first level of + * recursion and emit all of the resulting values, then expand all of these at a + * second level and so on... + *

+ * For example, given the hierarchical structure + *

+	 *  A
+	 *   - AA
+	 *     - aa1
+	 *   - AB
+	 *     - ab1
+	 *   - a1
+	 * 
+ * + * Expands {@code Mono.just(A)} into + *
+	 *  A
+	 *  AA
+	 *  AB
+	 *  a1
+	 *  aa1
+	 *  ab1
+	 * 
+ * + * @param expander the {@link Function} applied at each level of recursion to expand + * values into a {@link Publisher}, producing a graph. + * @param capacityHint a capacity hint to prepare the inner queues to accommodate n + * elements per level of recursion. + * + * @return this Mono expanded breadth-first to a {@link Flux} + */ + public final Flux expand(Function> expander, + int capacityHint) { + return Flux.onAssembly(new MonoExpand<>(this, expander, true, capacityHint)); + } + + /** + * Recursively expand elements into a graph and emit all the resulting element using + * a breadth-first traversal strategy. + *

+ * That is: emit the value from this {@link Mono} first, then expand it at a first level of + * recursion and emit all of the resulting values, then expand all of these at a + * second level and so on... + *

+ * For example, given the hierarchical structure + *

+	 *  A
+	 *   - AA
+	 *     - aa1
+	 *   - AB
+	 *     - ab1
+	 *   - a1
+	 * 
+ * + * Expands {@code Mono.just(A)} into + *
+	 *  A
+	 *  AA
+	 *  AB
+	 *  a1
+	 *  aa1
+	 *  ab1
+	 * 
+ * + * @param expander the {@link Function} applied at each level of recursion to expand + * values into a {@link Publisher}, producing a graph. + * + * @return this Mono expanded breadth-first to a {@link Flux} + */ + public final Flux expand(Function> expander) { + return expand(expander, Queues.SMALL_BUFFER_SIZE); + } + + /** + * If this {@link Mono} is valued, test the result and replay it if predicate returns true. + * Otherwise complete without value. + * + *

+ * + * + *

Discard Support: This operator discards the element if it does not match the filter. It + * also discards upon cancellation or error triggered by a data signal. + * + * @param tester the predicate to evaluate + * + * @return a filtered {@link Mono} + */ + public final Mono filter(final Predicate tester) { + if (this instanceof Fuseable) { + return onAssembly(new MonoFilterFuseable<>(this, tester)); + } + return onAssembly(new MonoFilter<>(this, tester)); + } + + /** + * If this {@link Mono} is valued, test the value asynchronously using a generated + * {@code Publisher} test. The value from the Mono is replayed if the + * first item emitted by the test is {@literal true}. It is dropped if the test is + * either empty or its first emitted value is {@literal false}. + *

+ * Note that only the first value of the test publisher is considered, and unless it + * is a {@link Mono}, test will be cancelled after receiving that first value. + * + *

+ * + * + *

Discard Support: This operator discards the element if it does not match the filter. It + * also discards upon cancellation or error triggered by a data signal. + * + * @param asyncPredicate the function generating a {@link Publisher} of {@link Boolean} + * to filter the Mono with + * + * @return a filtered {@link Mono} + */ + public final Mono filterWhen(Function> asyncPredicate) { + return onAssembly(new MonoFilterWhen<>(this, asyncPredicate)); + } + + /** + * Transform the item emitted by this {@link Mono} asynchronously, returning the + * value emitted by another {@link Mono} (possibly changing the value type). + * + *

+ * + * + * @param transformer the function to dynamically bind a new {@link Mono} + * @param the result type bound + * + * @return a new {@link Mono} with an asynchronously mapped value. + */ + public final Mono flatMap(Function> + transformer) { + return onAssembly(new MonoFlatMap<>(this, transformer)); + } + + /** + * Transform the item emitted by this {@link Mono} into a Publisher, then forward + * its emissions into the returned {@link Flux}. + * + *

+ * + * + * @param mapper the + * {@link Function} to produce a sequence of R from the eventual passed {@link Subscriber#onNext} + * @param the merged sequence type + * + * @return a new {@link Flux} as the sequence is not guaranteed to be single at most + */ + public final Flux flatMapMany(Function> mapper) { + return Flux.onAssembly(new MonoFlatMapMany<>(this, mapper)); + } + + /** + * Transform the signals emitted by this {@link Mono} into signal-specific Publishers, + * then forward the applicable Publisher's emissions into the returned {@link Flux}. + * + *

+ * + * + * @param mapperOnNext the {@link Function} to call on next data and returning a sequence to merge + * @param mapperOnError the {@link Function} to call on error signal and returning a sequence to merge + * @param mapperOnComplete the {@link Function} to call on complete signal and returning a sequence to merge + * @param the type of the produced inner sequence + * + * @return a new {@link Flux} as the sequence is not guaranteed to be single at most + * + * @see Flux#flatMap(Function, Function, Supplier) + */ + public final Flux flatMapMany(Function> mapperOnNext, + Function> mapperOnError, + Supplier> mapperOnComplete) { + return flux().flatMap(mapperOnNext, mapperOnError, mapperOnComplete); + } + + /** + * Transform the item emitted by this {@link Mono} into {@link Iterable}, then forward + * its elements into the returned {@link Flux}. + * The {@link Iterable#iterator()} method will be called at least once and at most twice. + * + *

+ * + *

+ * This operator inspects each {@link Iterable}'s {@link Spliterator} to assess if the iteration + * can be guaranteed to be finite (see {@link Operators#onDiscardMultiple(Iterator, boolean, Context)}). + * Since the default Spliterator wraps the Iterator we can have two {@link Iterable#iterator()} + * calls per iterable. This second invocation is skipped on a {@link Collection } however, a type which is + * assumed to be always finite. + * + *

Discard Support: Upon cancellation, this operator discards {@code T} elements it prefetched and, in + * some cases, attempts to discard remainder of the currently processed {@link Iterable} (if it can + * safely ensure the iterator is finite). Note that this means each {@link Iterable}'s {@link Iterable#iterator()} + * method could be invoked twice. + * + * @param mapper the {@link Function} to transform input item into a sequence {@link Iterable} + * @param the merged output sequence type + * + * @return a merged {@link Flux} + * + */ + public final Flux flatMapIterable(Function> mapper) { + return Flux.onAssembly(new MonoFlattenIterable<>(this, mapper, Integer + .MAX_VALUE, Queues.one())); + } + + /** + * Convert this {@link Mono} to a {@link Flux} + * + * @return a {@link Flux} variant of this {@link Mono} + */ + public final Flux flux() { + if (this instanceof Callable && !(this instanceof Fuseable.ScalarCallable)) { + @SuppressWarnings("unchecked") Callable thiz = (Callable) this; + return Flux.onAssembly(new FluxCallable<>(thiz)); + } + return Flux.from(this); + } + + /** + * Emit a single boolean true if this {@link Mono} has an element. + * + *

+ * + * + * @return a new {@link Mono} with true if a value is emitted and false + * otherwise + */ + public final Mono hasElement() { + return onAssembly(new MonoHasElement<>(this)); + } + + /** + * Handle the items emitted by this {@link Mono} by calling a biconsumer with the + * output sink for each onNext. At most one {@link SynchronousSink#next(Object)} + * call must be performed and/or 0 or 1 {@link SynchronousSink#error(Throwable)} or + * {@link SynchronousSink#complete()}. + *

+ * When the context-propagation library + * is available at runtime and the downstream {@link ContextView} is not empty, this operator implicitly uses the + * library to restore thread locals around the handler {@link BiConsumer}. Typically, this would be done in conjunction + * with the use of {@link #contextCapture()} operator down the chain. + * + * @param handler the handling {@link BiConsumer} + * @param the transformed type + * + * @return a transformed {@link Mono} + */ + public final Mono handle(BiConsumer> handler) { + if (this instanceof Fuseable) { + return onAssembly(new MonoHandleFuseable<>(this, handler)); + } + return onAssembly(new MonoHandle<>(this, handler)); + } + + /** + * Hides the identity of this {@link Mono} instance. + * + *

The main purpose of this operator is to prevent certain identity-based + * optimizations from happening, mostly for diagnostic purposes. + * + * @return a new {@link Mono} preventing {@link Publisher} / {@link Subscription} based Reactor optimizations + */ + public final Mono hide() { + return onAssembly(new MonoHide<>(this)); + } + + /** + * Ignores onNext signal (dropping it) and only propagates termination events. + * + *

+ * + *

+ * + *

Discard Support: This operator discards the source element. + * + * @return a new empty {@link Mono} representing the completion of this {@link Mono}. + */ + public final Mono ignoreElement() { + return onAssembly(new MonoIgnoreElement<>(this)); + } + + /** + * Observe all Reactive Streams signals and trace them using {@link Logger} support. + * Default will use {@link Level#INFO} and {@code java.util.logging}. + * If SLF4J is available, it will be used instead. + * + *

+ * + *

+ * The default log category will be "reactor.Mono", followed by a suffix generated from + * the source operator, e.g. "reactor.Mono.Map". + * + * @return a new {@link Mono} that logs signals + * + * @see Flux#log() + */ + public final Mono log() { + return log(null, Level.INFO); + } + + /** + * Observe all Reactive Streams signals and use {@link Logger} support to handle trace implementation. Default will + * use {@link Level#INFO} and java.util.logging. If SLF4J is available, it will be used instead. + * + *

+ * + * + * @param category to be mapped into logger configuration (e.g. org.springframework + * .reactor). If category ends with "." like "reactor.", a generated operator + * suffix will complete, e.g. "reactor.Flux.Map". + * + * @return a new {@link Mono} + */ + public final Mono log(@Nullable String category) { + return log(category, Level.INFO); + } + + /** + * Observe Reactive Streams signals matching the passed flags {@code options} and use + * {@link Logger} support to handle trace implementation. Default will use the passed + * {@link Level} and java.util.logging. If SLF4J is available, it will be used instead. + * + * Options allow fine grained filtering of the traced signal, for instance to only capture onNext and onError: + *

+	 *     mono.log("category", SignalType.ON_NEXT, SignalType.ON_ERROR)
+	 * 
+ *

+ * + * + * @param category to be mapped into logger configuration (e.g. org.springframework + * .reactor). If category ends with "." like "reactor.", a generated operator + * suffix will complete, e.g. "reactor.Flux.Map". + * @param level the {@link Level} to enforce for this tracing Mono (only FINEST, FINE, + * INFO, WARNING and SEVERE are taken into account) + * @param options a vararg {@link SignalType} option to filter log messages + * + * @return a new {@link Mono} + * + */ + public final Mono log(@Nullable String category, Level level, SignalType... options) { + return log(category, level, false, options); + } + + /** + * Observe Reactive Streams signals matching the passed filter {@code options} and + * use {@link Logger} support to + * handle trace + * implementation. Default will + * use the passed {@link Level} and java.util.logging. If SLF4J is available, it will be used instead. + * + * Options allow fine grained filtering of the traced signal, for instance to only capture onNext and onError: + *

+	 *     mono.log("category", Level.INFO, SignalType.ON_NEXT, SignalType.ON_ERROR)
+	 * 
+ *

+ * + * + * @param category to be mapped into logger configuration (e.g. org.springframework + * .reactor). If category ends with "." like "reactor.", a generated operator + * suffix will complete, e.g. "reactor.Mono.Map". + * @param level the {@link Level} to enforce for this tracing Mono (only FINEST, FINE, + * INFO, WARNING and SEVERE are taken into account) + * @param showOperatorLine capture the current stack to display operator + * class/line number. + * @param options a vararg {@link SignalType} option to filter log messages + * + * @return a new unaltered {@link Mono} + */ + public final Mono log(@Nullable String category, + Level level, + boolean showOperatorLine, + SignalType... options) { + SignalLogger log = new SignalLogger<>(this, category, level, + showOperatorLine, options); + + if (this instanceof Fuseable) { + return onAssembly(new MonoLogFuseable<>(this, log)); + } + return onAssembly(new MonoLog<>(this, log)); + } + + + /** + * Observe Reactive Streams signals matching the passed filter {@code options} and + * trace them using a specific user-provided {@link Logger}, at {@link Level#INFO} level. + *

+ * + * + * @param logger the {@link Logger} to use, instead of resolving one through a category. + * + * @return a new {@link Mono} that logs signals + */ + public final Mono log(Logger logger) { + return log(logger, Level.INFO, false); + } + + /** + * Observe Reactive Streams signals matching the passed filter {@code options} and + * trace them using a specific user-provided {@link Logger}, at the given {@link Level}. + *

+ * Options allow fine grained filtering of the traced signal, for instance to only + * capture onNext and onError: + *

+	 *     flux.log(myCustomLogger, Level.INFO, SignalType.ON_NEXT, SignalType.ON_ERROR)
+	 * 
+ *

+ * + * + * @param logger the {@link Logger} to use, instead of resolving one through a category. + * @param level the {@link Level} to enforce for this tracing Flux (only FINEST, FINE, + * INFO, WARNING and SEVERE are taken into account) + * @param showOperatorLine capture the current stack to display operator class/line number. + * @param options a vararg {@link SignalType} option to filter log messages + * + * @return a new {@link Mono} that logs signals + */ + public final Mono log(Logger logger, + Level level, + boolean showOperatorLine, + SignalType... options) { + SignalLogger log = new SignalLogger<>(this, "IGNORED", level, + showOperatorLine, + s -> logger, + options); + + if (this instanceof Fuseable) { + return onAssembly(new MonoLogFuseable<>(this, log)); + } + return onAssembly(new MonoLog<>(this, log)); + } + + /** + * Transform the item emitted by this {@link Mono} by applying a synchronous function to it. + * + *

+ * + * + * @param mapper the synchronous transforming {@link Function} + * @param the transformed type + * + * @return a new {@link Mono} + */ + public final Mono map(Function mapper) { + if (this instanceof Fuseable) { + return onAssembly(new MonoMapFuseable<>(this, mapper)); + } + return onAssembly(new MonoMap<>(this, mapper)); + } + + /** + * Transform the item emitted by this {@link Mono} by applying a synchronous function to it, which is allowed + * to produce a {@code null} value. In that case, the resulting Mono completes immediately. + * This operator effectively behaves like {@link #map(Function)} followed by {@link #filter(Predicate)} + * although {@code null} is not a supported value, so it can't be filtered out. + * + *

+ * + * + * @param mapper the synchronous transforming {@link Function} + * @param the transformed type + * + * @return a new {@link Mono} + */ + public final Mono mapNotNull(Function mapper) { + return this.handle((t, sink) -> { + R r = mapper.apply(t); + if (r != null) { + sink.next(r); + } + }); + } + + /** + * Transform incoming onNext, onError and onComplete signals into {@link Signal} instances, + * materializing these signals. + * Since the error is materialized as a {@code Signal}, the propagation will be stopped and onComplete will be + * emitted. Complete signal will first emit a {@code Signal.complete()} and then effectively complete the flux. + * All these {@link Signal} have a {@link Context} associated to them. + *

+ * + * + * @return a {@link Mono} of materialized {@link Signal} + * @see #dematerialize() + */ + public final Mono> materialize() { + return onAssembly(new MonoMaterialize<>(this)); + } + + /** + * Merge emissions of this {@link Mono} with the provided {@link Publisher}. + * The element from the Mono may be interleaved with the elements of the Publisher. + * + *

+ * + * + * @param other the {@link Publisher} to merge with + * + * @return a new {@link Flux} as the sequence is not guaranteed to be at most 1 + */ + public final Flux mergeWith(Publisher other) { + return Flux.merge(this, other); + } + + /** + * Activate metrics for this sequence, provided there is an instrumentation facade + * on the classpath (otherwise this method is a pure no-op). + *

+ * Metrics are gathered on {@link Subscriber} events, and it is recommended to also + * {@link #name(String) name} (and optionally {@link #tag(String, String) tag}) the + * sequence. + *

+ * The name serves as a prefix in the reported metrics names. In case no name has been provided, the default name "reactor" will be applied. + *

+ * The {@link MeterRegistry} used by reactor can be configured via + * {@link reactor.util.Metrics.MicrometerConfiguration#useRegistry(MeterRegistry)} + * prior to using this operator, the default being + * {@link io.micrometer.core.instrument.Metrics#globalRegistry}. + *

+ * + * @return an instrumented {@link Mono} + * + * @see #name(String) + * @see #tag(String, String) + * @deprecated Prefer using the {@link #tap(SignalListenerFactory)} with the {@link SignalListenerFactory} provided by + * the new reactor-core-micrometer module. To be removed in 3.6.0 at the earliest. + */ + @Deprecated + public final Mono metrics() { + if (!Metrics.isInstrumentationAvailable()) { + return this; + } + + if (this instanceof Fuseable) { + return onAssembly(new MonoMetricsFuseable<>(this)); + } + return onAssembly(new MonoMetrics<>(this)); + } + + /** + * Give a name to this sequence, which can be retrieved using {@link Scannable#name()} + * as long as this is the first reachable {@link Scannable#parents()}. + *

+ * The name is typically visible at assembly time by the {@link #tap(SignalListenerFactory)} operator, + * which could for example be configured with a metrics listener using the name as a prefix for meters' id. + * + * @param name a name for the sequence + * + * @return the same sequence, but bearing a name + * + * @see #metrics() + * @see #tag(String, String) + */ + public final Mono name(String name) { + return MonoName.createOrAppend(this, name); + } + + /** + * Emit the first available signal from this mono or the other mono. + * + *

+ * + * + * @param other the racing other {@link Mono} to compete with for the signal + * + * @return a new {@link Mono} + * @see #firstWithSignal + */ + public final Mono or(Mono other) { + if (this instanceof MonoFirstWithSignal) { + MonoFirstWithSignal a = (MonoFirstWithSignal) this; + Mono result = a.orAdditionalSource(other); + if (result != null) { + return result; + } + } + return firstWithSignal(this, other); + } + + /** + * Evaluate the emitted value against the given {@link Class} type. If the + * value matches the type, it is passed into the new {@link Mono}. Otherwise the + * value is ignored. + * + *

+ * + * + * @param clazz the {@link Class} type to test values against + * + * @return a new {@link Mono} filtered on the requested type + */ + public final Mono ofType(final Class clazz) { + Objects.requireNonNull(clazz, "clazz"); + return filter(o -> clazz.isAssignableFrom(o.getClass())).cast(clazz); + } + + /** + * Simply complete the sequence by replacing an {@link Subscriber#onError(Throwable) onError signal} + * with an {@link Subscriber#onComplete() onComplete signal}. All other signals are propagated as-is. + * + *

+ * + * + * @return a new {@link Mono} falling back on completion when an onError occurs + * @see #onErrorReturn(Object) + */ + public final Mono onErrorComplete() { + return onAssembly(new MonoOnErrorReturn<>(this, null, null)); + } + + /** + * Simply complete the sequence by replacing an {@link Subscriber#onError(Throwable) onError signal} + * with an {@link Subscriber#onComplete() onComplete signal} if the error matches the given + * {@link Class}. All other signals, including non-matching onError, are propagated as-is. + * + *

+ * + * + * @return a new {@link Mono} falling back on completion when a matching error occurs + * @see #onErrorReturn(Class, Object) + */ + public final Mono onErrorComplete(Class type) { + Objects.requireNonNull(type, "type must not be null"); + return onErrorComplete(type::isInstance); + } + + /** + * Simply complete the sequence by replacing an {@link Subscriber#onError(Throwable) onError signal} + * with an {@link Subscriber#onComplete() onComplete signal} if the error matches the given + * {@link Predicate}. All other signals, including non-matching onError, are propagated as-is. + * + *

+ * + * + * @return a new {@link Mono} falling back on completion when a matching error occurs + * @see #onErrorReturn(Predicate, Object) + */ + public final Mono onErrorComplete(Predicate predicate) { + Objects.requireNonNull(predicate, "predicate must not be null"); + return onAssembly(new MonoOnErrorReturn<>(this, predicate, null)); + } + + /** + * Let compatible operators upstream recover from errors by dropping the + * incriminating element from the sequence and continuing with subsequent elements. + * The recovered error and associated value are notified via the provided {@link BiConsumer}. + * Alternatively, throwing from that biconsumer will propagate the thrown exception downstream + * in place of the original error, which is added as a suppressed exception to the new one. + *

+ * This operator is offered on {@link Mono} mainly as a way to propagate the configuration to + * upstream {@link Flux}. The mode doesn't really make sense on a {@link Mono}, since we're sure + * there will be no further value to continue with. + * {@link #onErrorResume(Function)} is a more classical fit. + *

+ * Note that onErrorContinue() is a specialist operator that can make the behaviour of your + * reactive chain unclear. It operates on upstream, not downstream operators, it requires specific + * operator support to work, and the scope can easily propagate upstream into library code + * that didn't anticipate it (resulting in unintended behaviour.) + *

+ * In most cases, you should instead handle the error inside the specific function which may cause + * it. Specifically, on each inner publisher you can use {@code doOnError} to log the error, and + * {@code onErrorResume(e -> Mono.empty())} to drop erroneous elements: + *

+ *

+	 * .flatMap(id -> repository.retrieveById(id)
+	 *                          .doOnError(System.err::println)
+	 *                          .onErrorResume(e -> Mono.empty()))
+	 * 
+ *

+ * This has the advantage of being much clearer, has no ambiguity with regards to operator support, + * and cannot leak upstream. + * + * @param errorConsumer a {@link BiConsumer} fed with errors matching the {@link Class} + * and the value that triggered the error. + * @return a {@link Mono} that attempts to continue processing on errors. + */ + public final Mono onErrorContinue(BiConsumer errorConsumer) { + BiConsumer genericConsumer = errorConsumer; + return contextWrite(Context.of( + OnNextFailureStrategy.KEY_ON_NEXT_ERROR_STRATEGY, + OnNextFailureStrategy.resume(genericConsumer) + )); + } + + /** + * Let compatible operators upstream recover from errors by dropping the + * incriminating element from the sequence and continuing with subsequent elements. + * Only errors matching the specified {@code type} are recovered from. + * The recovered error and associated value are notified via the provided {@link BiConsumer}. + * Alternatively, throwing from that biconsumer will propagate the thrown exception downstream + * in place of the original error, which is added as a suppressed exception to the new one. + *

+ * This operator is offered on {@link Mono} mainly as a way to propagate the configuration to + * upstream {@link Flux}. The mode doesn't really make sense on a {@link Mono}, since we're sure + * there will be no further value to continue with. + * {@link #onErrorResume(Function)} is a more classical fit. + *

+ * Note that onErrorContinue() is a specialist operator that can make the behaviour of your + * reactive chain unclear. It operates on upstream, not downstream operators, it requires specific + * operator support to work, and the scope can easily propagate upstream into library code + * that didn't anticipate it (resulting in unintended behaviour.) + *

+ * In most cases, you should instead handle the error inside the specific function which may cause + * it. Specifically, on each inner publisher you can use {@code doOnError} to log the error, and + * {@code onErrorResume(e -> Mono.empty())} to drop erroneous elements: + *

+ *

+	 * .flatMap(id -> repository.retrieveById(id)
+	 *                          .doOnError(MyException.class, System.err::println)
+	 *                          .onErrorResume(MyException.class, e -> Mono.empty()))
+	 * 
+ *

+ * This has the advantage of being much clearer, has no ambiguity with regards to operator support, + * and cannot leak upstream. + * + * @param type the {@link Class} of {@link Exception} that are resumed from. + * @param errorConsumer a {@link BiConsumer} fed with errors matching the {@link Class} + * and the value that triggered the error. + * @return a {@link Mono} that attempts to continue processing on some errors. + */ + public final Mono onErrorContinue(Class type, BiConsumer errorConsumer) { + return onErrorContinue(type::isInstance, errorConsumer); + } + + /** + * Let compatible operators upstream recover from errors by dropping the + * incriminating element from the sequence and continuing with subsequent elements. + * Only errors matching the {@link Predicate} are recovered from (note that this + * predicate can be applied several times and thus must be idempotent). + * The recovered error and associated value are notified via the provided {@link BiConsumer}. + * Alternatively, throwing from that biconsumer will propagate the thrown exception downstream + * in place of the original error, which is added as a suppressed exception to the new one. + *

+ * This operator is offered on {@link Mono} mainly as a way to propagate the configuration to + * upstream {@link Flux}. The mode doesn't really make sense on a {@link Mono}, since we're sure + * there will be no further value to continue with. + * {@link #onErrorResume(Function)} is a more classical fit. + *

+ * Note that onErrorContinue() is a specialist operator that can make the behaviour of your + * reactive chain unclear. It operates on upstream, not downstream operators, it requires specific + * operator support to work, and the scope can easily propagate upstream into library code + * that didn't anticipate it (resulting in unintended behaviour.) + *

+ * In most cases, you should instead handle the error inside the specific function which may cause + * it. Specifically, on each inner publisher you can use {@code doOnError} to log the error, and + * {@code onErrorResume(e -> Mono.empty())} to drop erroneous elements: + *

+ *

+	 * .flatMap(id -> repository.retrieveById(id)
+	 *                          .doOnError(errorPredicate, System.err::println)
+	 *                          .onErrorResume(errorPredicate, e -> Mono.empty()))
+	 * 
+ *

+ * This has the advantage of being much clearer, has no ambiguity with regards to operator support, + * and cannot leak upstream. + * + * @param errorPredicate a {@link Predicate} used to filter which errors should be resumed from. + * This MUST be idempotent, as it can be used several times. + * @param errorConsumer a {@link BiConsumer} fed with errors matching the predicate and the value + * that triggered the error. + * @return a {@link Mono} that attempts to continue processing on some errors. + */ + public final Mono onErrorContinue(Predicate errorPredicate, + BiConsumer errorConsumer) { + //this cast is ok as only T values will be propagated in this sequence + @SuppressWarnings("unchecked") + Predicate genericPredicate = (Predicate) errorPredicate; + BiConsumer genericErrorConsumer = errorConsumer; + return contextWrite(Context.of( + OnNextFailureStrategy.KEY_ON_NEXT_ERROR_STRATEGY, + OnNextFailureStrategy.resumeIf(genericPredicate, genericErrorConsumer) + )); + } + + /** + * If an {@link #onErrorContinue(BiConsumer)} variant has been used downstream, reverts + * to the default 'STOP' mode where errors are terminal events upstream. It can be + * used for easier scoping of the on next failure strategy or to override the + * inherited strategy in a sub-stream (for example in a flatMap). It has no effect if + * {@link #onErrorContinue(BiConsumer)} has not been used downstream. + * + * @return a {@link Mono} that terminates on errors, even if {@link #onErrorContinue(BiConsumer)} + * was used downstream + */ + public final Mono onErrorStop() { + return contextWrite(Context.of( + OnNextFailureStrategy.KEY_ON_NEXT_ERROR_STRATEGY, + OnNextFailureStrategy.stop())); + } + + /** + * Transform an error emitted by this {@link Mono} by synchronously applying a function + * to it if the error matches the given predicate. Otherwise let the error pass through. + *

+ * + * + * @param predicate the error predicate + * @param mapper the error transforming {@link Function} + * + * @return a {@link Mono} that transforms some source errors to other errors + */ + public final Mono onErrorMap(Predicate predicate, + Function mapper) { + return onErrorResume(predicate, e -> Mono.error(mapper.apply(e))); + } + + + /** + * Transform any error emitted by this {@link Mono} by synchronously applying a function to it. + *

+ * + * + * @param mapper the error transforming {@link Function} + * + * @return a {@link Mono} that transforms source errors to other errors + */ + public final Mono onErrorMap(Function mapper) { + return onErrorResume(e -> Mono.error(mapper.apply(e))); + } + + /** + * Transform an error emitted by this {@link Mono} by synchronously applying a function + * to it if the error matches the given type. Otherwise let the error pass through. + *

+ * + * + * @param type the class of the exception type to react to + * @param mapper the error transforming {@link Function} + * @param the error type + * + * @return a {@link Mono} that transforms some source errors to other errors + */ + public final Mono onErrorMap(Class type, + Function mapper) { + @SuppressWarnings("unchecked") + Function handler = (Function)mapper; + return onErrorMap(type::isInstance, handler); + } + + /** + * Subscribe to a fallback publisher when any error occurs, using a function to + * choose the fallback depending on the error. + * + *

+ * + * + * @param fallback the function to choose the fallback to an alternative {@link Mono} + * + * @return a {@link Mono} falling back upon source onError + * + * @see Flux#onErrorResume + */ + public final Mono onErrorResume(Function> fallback) { + return onAssembly(new MonoOnErrorResume<>(this, fallback)); + } + + /** + * Subscribe to a fallback publisher when an error matching the given type + * occurs, using a function to choose the fallback depending on the error. + *

+ * + * + * @param type the error type to match + * @param fallback the function to choose the fallback to an alternative {@link Mono} + * @param the error type + * + * @return a {@link Mono} falling back upon source onError + * @see Flux#onErrorResume + */ + public final Mono onErrorResume(Class type, + Function> fallback) { + Objects.requireNonNull(type, "type"); + @SuppressWarnings("unchecked") + Function> handler = (Function>)fallback; + return onErrorResume(type::isInstance, handler); + } + + /** + * Subscribe to a fallback publisher when an error matching a given predicate + * occurs. + *

+ * + * + * @param predicate the error predicate to match + * @param fallback the function to choose the fallback to an alternative {@link Mono} + * @return a {@link Mono} falling back upon source onError + * @see Flux#onErrorResume + */ + public final Mono onErrorResume(Predicate predicate, + Function> fallback) { + Objects.requireNonNull(predicate, "predicate"); + return onErrorResume(e -> predicate.test(e) ? fallback.apply(e) : error(e)); + } + + /** + * Simply emit a captured fallback value when any error is observed on this {@link Mono}. + * + *

+ * + * + * @param fallbackValue the value to emit if an error occurs + * + * @return a new falling back {@link Mono} + * @see #onErrorComplete() + */ + public final Mono onErrorReturn(final T fallbackValue) { + Objects.requireNonNull(fallbackValue, "fallbackValue must not be null"); + return onAssembly(new MonoOnErrorReturn<>(this, null, fallbackValue)); + } + + /** + * Simply emit a captured fallback value when an error of the specified type is + * observed on this {@link Mono}. + *

+ * + * + * @param type the error type to match + * @param fallbackValue the value to emit if an error occurs that matches the type + * @param the error type + * + * @return a new falling back {@link Mono} + * @see #onErrorComplete(Class) + */ + public final Mono onErrorReturn(Class type, T fallbackValue) { + Objects.requireNonNull(type, "type must not be null"); + Objects.requireNonNull(fallbackValue, "fallbackValue must not be null"); + return onErrorReturn(type::isInstance, fallbackValue); + } + + /** + * Simply emit a captured fallback value when an error matching the given predicate is + * observed on this {@link Mono}. + *

+ * + * + * @param predicate the error predicate to match + * @param fallbackValue the value to emit if an error occurs that matches the predicate + * + * @return a new {@link Mono} + * @see #onErrorComplete(Predicate) + */ + public final Mono onErrorReturn(Predicate predicate, T fallbackValue) { + Objects.requireNonNull(predicate, "predicate must not be null"); + Objects.requireNonNull(fallbackValue, "fallbackValue must not be null"); + return onAssembly(new MonoOnErrorReturn<>(this, predicate, fallbackValue)); + } + + /** + * Detaches both the child {@link Subscriber} and the {@link Subscription} on + * termination or cancellation. + *

This should help with odd retention scenarios when running + * with non-reactor {@link Subscriber}. + * + * @return a detachable {@link Mono} + */ + public final Mono onTerminateDetach() { + return new MonoDetach<>(this); + } + + /** + * Share a {@link Mono} for the duration of a function that may transform it and + * consume it as many times as necessary without causing multiple subscriptions + * to the upstream. + * + * @param transform the transformation function + * @param the output value type + * + * @return a new {@link Mono} + */ + public final Mono publish(Function, ? extends Mono> transform) { + return onAssembly(new MonoPublishMulticast<>(this, transform)); + } + + /** + * Run onNext, onComplete and onError on a supplied {@link Scheduler} + * {@link Worker Worker}. + *

+ * This operator influences the threading context where the rest of the operators in + * the chain below it will execute, up to a new occurrence of {@code publishOn}. + *

+ * + *

+ * Typically used for fast publisher, slow consumer(s) scenarios. + * + *

+	 * {@code mono.publishOn(Schedulers.single()).subscribe() }
+	 * 
+ * + * @param scheduler a {@link Scheduler} providing the {@link Worker} where to publish + * + * @return an asynchronously producing {@link Mono} + */ + public final Mono publishOn(Scheduler scheduler) { + if(this instanceof Callable) { + if (this instanceof Fuseable.ScalarCallable) { + try { + T value = block(); + return onAssembly(new MonoSubscribeOnValue<>(value, scheduler)); + } + catch (Throwable t) { + //leave MonoSubscribeOnCallable defer error + } + } + @SuppressWarnings("unchecked") + Callable c = (Callable)this; + return onAssembly(new MonoSubscribeOnCallable<>(c, scheduler)); + } + return onAssembly(new MonoPublishOn<>(this, scheduler)); + } + + /** + * Repeatedly and indefinitely subscribe to the source upon completion of the + * previous subscription. + * + *

+ * + * + * @return an indefinitely repeated {@link Flux} on onComplete + */ + public final Flux repeat() { + return repeat(Flux.ALWAYS_BOOLEAN_SUPPLIER); + } + + /** + * Repeatedly subscribe to the source if the predicate returns true after completion of the previous subscription. + * + *

+ * + * + * @param predicate the boolean to evaluate on onComplete. + * + * @return a {@link Flux} that repeats on onComplete while the predicate matches + * + */ + public final Flux repeat(BooleanSupplier predicate) { + return Flux.onAssembly(new MonoRepeatPredicate<>(this, predicate)); + } + + /** + * Repeatedly subscribe to the source {@literal numRepeat} times. This results in + * {@code numRepeat + 1} total subscriptions to the original source. As a consequence, + * using 0 plays the original sequence once. + * + *

+ * + * + * @param numRepeat the number of times to re-subscribe on onComplete (positive, or 0 for original sequence only) + * @return a {@link Flux} that repeats on onComplete, up to the specified number of repetitions + */ + public final Flux repeat(long numRepeat) { + if (numRepeat == 0) { + return this.flux(); + } + return Flux.onAssembly(new MonoRepeat<>(this, numRepeat)); + } + + /** + * Repeatedly subscribe to the source if the predicate returns true after completion of the previous + * subscription. A specified maximum of repeat will limit the number of re-subscribe. + * + *

+ * + * + * @param numRepeat the number of times to re-subscribe on complete (positive, or 0 for original sequence only) + * @param predicate the boolean to evaluate on onComplete + * + * @return a {@link Flux} that repeats on onComplete while the predicate matches, + * up to the specified number of repetitions + */ + public final Flux repeat(long numRepeat, BooleanSupplier predicate) { + if (numRepeat < 0L) { + throw new IllegalArgumentException("numRepeat >= 0 required"); + } + if (numRepeat == 0) { + return this.flux(); + } + return Flux.defer(() -> repeat(Flux.countingBooleanSupplier(predicate, numRepeat))); + } + + /** + * Repeatedly subscribe to this {@link Mono} when a companion sequence emits elements in + * response to the flux completion signal. Any terminal signal from the companion + * sequence will terminate the resulting {@link Flux} with the same signal immediately. + *

If the companion sequence signals when this {@link Mono} is active, the repeat + * attempt is suppressed. + * + *

+ * + *

+ * Note that if the companion {@link Publisher} created by the {@code repeatFactory} + * emits {@link Context} as trigger objects, the content of these Context will be added + * to the operator's own {@link Context}. + * + * @param repeatFactory the {@link Function} that returns the associated {@link Publisher} + * companion, given a {@link Flux} that signals each onComplete as a {@link Long} + * representing the number of source elements emitted in the latest attempt (0 or 1). + * + * @return a {@link Flux} that repeats on onComplete when the companion {@link Publisher} produces an + * onNext signal + */ + public final Flux repeatWhen(Function, ? extends Publisher> repeatFactory) { + return Flux.onAssembly(new MonoRepeatWhen<>(this, repeatFactory)); + } + + /** + * Repeatedly subscribe to this {@link Mono} as long as the current subscription to this + * {@link Mono} completes empty and the companion {@link Publisher} produces an onNext signal. + *

+ * Any terminal signal will terminate the resulting {@link Mono} with the same signal immediately. + * + *

+ * + * + * @param repeatFactory the {@link Function} that returns the associated {@link Publisher} + * companion, given a {@link Flux} that signals each onComplete as a 0-based incrementing {@link Long}. + * + * @return a {@link Mono} that resubscribes to this {@link Mono} if the previous subscription was empty, + * as long as the companion {@link Publisher} produces an onNext signal + * + */ + public final Mono repeatWhenEmpty(Function, ? extends Publisher> repeatFactory) { + return repeatWhenEmpty(Integer.MAX_VALUE, repeatFactory); + } + + /** + * Repeatedly subscribe to this {@link Mono} as long as the current subscription to this + * {@link Mono} completes empty and the companion {@link Publisher} produces an onNext signal. + *

+ * Any terminal signal will terminate the resulting {@link Mono} with the same signal immediately. + *

+ * Emits an {@link IllegalStateException} if {@code maxRepeat} is exceeded (provided + * it is different from {@code Integer.MAX_VALUE}). + * + *

+ * + * + * @param maxRepeat the maximum number of repeats (infinite if {@code Integer.MAX_VALUE}) + * @param repeatFactory the {@link Function} that returns the associated {@link Publisher} + * companion, given a {@link Flux} that signals each onComplete as a 0-based incrementing {@link Long}. + * + * @return a {@link Mono} that resubscribes to this {@link Mono} if the previous subscription was empty, + * as long as the companion {@link Publisher} produces an onNext signal and the maximum number of repeats isn't exceeded. + */ + public final Mono repeatWhenEmpty(int maxRepeat, Function, ? extends Publisher> repeatFactory) { + return Mono.defer(() -> this.repeatWhen(o -> { + if (maxRepeat == Integer.MAX_VALUE) { + return repeatFactory.apply(o.index().map(Tuple2::getT1)); + } + else { + return repeatFactory.apply(o + .index() + .map(Tuple2::getT1) + .take(maxRepeat, false) + .concatWith(Flux.error(() -> new IllegalStateException("Exceeded maximum number of repeats")))); + } + }).next()); + } + + + /** + * Re-subscribes to this {@link Mono} sequence if it signals any error, indefinitely. + *

+ * + * + * @return a {@link Mono} that retries on onError + */ + public final Mono retry() { + return retry(Long.MAX_VALUE); + } + + /** + * Re-subscribes to this {@link Mono} sequence if it signals any error, for a fixed + * number of times. + *

+ * Note that passing {@literal Long.MAX_VALUE} is treated as infinite retry. + *

+ * + * + * @param numRetries the number of times to tolerate an error + * + * @return a {@link Mono} that retries on onError up to the specified number of retry attempts. + */ + public final Mono retry(long numRetries) { + return onAssembly(new MonoRetry<>(this, numRetries)); + } + + /** + * Retries this {@link Mono} in response to signals emitted by a companion {@link Publisher}. + * The companion is generated by the provided {@link Retry} instance, see {@link Retry#max(long)}, {@link Retry#maxInARow(long)} + * and {@link Retry#backoff(long, Duration)} for readily available strategy builders. + *

+ * The operator generates a base for the companion, a {@link Flux} of {@link reactor.util.retry.Retry.RetrySignal} + * which each give metadata about each retryable failure whenever this {@link Mono} signals an error. The final companion + * should be derived from that base companion and emit data in response to incoming onNext (although it can emit less + * elements, or delay the emissions). + *

+ * Terminal signals in the companion terminate the sequence with the same signal, so emitting an {@link Subscriber#onError(Throwable)} + * will fail the resulting {@link Mono} with that same error. + *

+ * + *

+ * Note that the {@link reactor.util.retry.Retry.RetrySignal} state can be transient and change between each source + * {@link org.reactivestreams.Subscriber#onError(Throwable) onError} or + * {@link org.reactivestreams.Subscriber#onNext(Object) onNext}. If processed with a delay, + * this could lead to the represented state being out of sync with the state at which the retry + * was evaluated. Map it to {@link reactor.util.retry.Retry.RetrySignal#copy()} right away to mediate this. + *

+ * Note that if the companion {@link Publisher} created by the {@code whenFactory} + * emits {@link Context} as trigger objects, these {@link Context} will be merged with + * the previous Context: + *

+ *
+	 * {@code
+	 * Retry customStrategy = Retry.from(companion -> companion.handle((retrySignal, sink) -> {
+	 * 	    Context ctx = sink.currentContext();
+	 * 	    int rl = ctx.getOrDefault("retriesLeft", 0);
+	 * 	    if (rl > 0) {
+	 *		    sink.next(Context.of(
+	 *		        "retriesLeft", rl - 1,
+	 *		        "lastError", retrySignal.failure()
+	 *		    ));
+	 * 	    } else {
+	 * 	        sink.error(Exceptions.retryExhausted("retries exhausted", retrySignal.failure()));
+	 * 	    }
+	 * }));
+	 * Mono retried = originalMono.retryWhen(customStrategy);
+	 * }
+ *
+ * + * @param retrySpec the {@link Retry} strategy that will generate the companion {@link Publisher}, + * given a {@link Flux} that signals each onError as a {@link reactor.util.retry.Retry.RetrySignal}. + * + * @return a {@link Mono} that retries on onError when a companion {@link Publisher} produces an onNext signal + * @see Retry#max(long) + * @see Retry#maxInARow(long) + * @see Retry#backoff(long, Duration) + */ + public final Mono retryWhen(Retry retrySpec) { + return onAssembly(new MonoRetryWhen<>(this, retrySpec)); + } + + /** + * Prepare a {@link Mono} which shares this {@link Mono} result similar to {@link Flux#shareNext()}. + * This will effectively turn this {@link Mono} into a hot task when the first + * {@link Subscriber} subscribes using {@link #subscribe()} API. Further {@link Subscriber} will share the same {@link Subscription} + * and therefore the same result. + * It's worth noting this is an un-cancellable {@link Subscription}. + *

+ * + * + * @return a new {@link Mono} + */ + public final Mono share() { + if (this instanceof Fuseable.ScalarCallable) { + return this; + } + + if (this instanceof NextProcessor && ((NextProcessor) this).isRefCounted) { //TODO should we check whether the NextProcessor has a source or not? + return this; + } + return new NextProcessor<>(this, true); + } + + /** + * Expect exactly one item from this {@link Mono} source or signal + * {@link java.util.NoSuchElementException} for an empty source. + *

+ * + *

+ * Note Mono doesn't need {@link Flux#single(Object)}, since it is equivalent to + * {@link #defaultIfEmpty(Object)} in a {@link Mono}. + * + * @return a {@link Mono} with the single item or an error signal + */ + public final Mono single() { + if (this instanceof Callable) { + if (this instanceof Fuseable.ScalarCallable) { + @SuppressWarnings("unchecked") + Fuseable.ScalarCallable scalarCallable = (Fuseable.ScalarCallable) this; + + T v; + try { + v = scalarCallable.call(); + } + catch (Exception e) { + return Mono.error(Exceptions.unwrap(e)); + } + if (v == null) { + return Mono.error(new NoSuchElementException("Source was a (constant) empty")); + } + return Mono.just(v); + } + @SuppressWarnings("unchecked") + Callable thiz = (Callable)this; + return Mono.onAssembly(new MonoSingleCallable<>(thiz)); + } + return Mono.onAssembly(new MonoSingleMono<>(this)); + } + + /** + * Wrap the item produced by this {@link Mono} source into an Optional + * or emit an empty Optional for an empty source. + *

+ * + * @return a {@link Mono} with an Optional containing the item, an empty optional or an error signal + */ + public final Mono> singleOptional() { + if (this instanceof Callable) { + if (this instanceof Fuseable.ScalarCallable) { + @SuppressWarnings("unchecked") + Fuseable.ScalarCallable scalarCallable = (Fuseable.ScalarCallable) this; + + T v; + try { + v = scalarCallable.call(); + } + catch (Exception e) { + return Mono.error(Exceptions.unwrap(e)); + } + return Mono.just(Optional.ofNullable(v)); + } + @SuppressWarnings("unchecked") + Callable thiz = (Callable)this; + return Mono.onAssembly(new MonoSingleOptionalCallable<>(thiz)); + } + return Mono.onAssembly(new MonoSingleOptional<>(this)); + } + + /** + * Subscribe to this {@link Mono} and request unbounded demand. + *

+ * This version doesn't specify any consumption behavior for the events from the + * chain, especially no error handling, so other variants should usually be preferred. + * + *

+ * + * + * @return a new {@link Disposable} that can be used to cancel the underlying {@link Subscription} + */ + public final Disposable subscribe() { + if(this instanceof NextProcessor){ + NextProcessor s = (NextProcessor)this; + // Mono#share() should return a new lambda subscriber during subscribe. + // This can now be precisely detected with source != null in combination to the isRefCounted boolean being true. + // `Sinks.one().subscribe()` case is now split into a separate implementation. + // Otherwise, this is a (legacy) #toProcessor() usage, and we return the processor itself below (and don't forget to connect() it): + if (s.source != null && !s.isRefCounted) { + s.subscribe(new LambdaMonoSubscriber<>(null, null, null, null, null)); + s.connect(); + return s; + } + } + return subscribeWith(new LambdaMonoSubscriber<>(null, null, null, null, null)); + } + + /** + * Subscribe a {@link Consumer} to this {@link Mono} that will consume all the + * sequence. It will request an unbounded demand ({@code Long.MAX_VALUE}). + *

+ * For a passive version that observe and forward incoming data see {@link #doOnNext(java.util.function.Consumer)}. + *

+ * Keep in mind that since the sequence can be asynchronous, this will immediately + * return control to the calling thread. This can give the impression the consumer is + * not invoked when executing in a main thread or a unit test for instance. + * + *

+ * + * + * @param consumer the consumer to invoke on each value (onNext signal) + * + * @return a new {@link Disposable} that can be used to cancel the underlying {@link Subscription} + */ + public final Disposable subscribe(Consumer consumer) { + Objects.requireNonNull(consumer, "consumer"); + return subscribe(consumer, null, null); + } + + /** + * Subscribe to this {@link Mono} with a {@link Consumer} that will consume all the + * elements in the sequence, as well as a {@link Consumer} that will handle errors. + * The subscription will request an unbounded demand ({@code Long.MAX_VALUE}). + *

+ * For a passive version that observe and forward incoming data see {@link #doOnSuccess(Consumer)} and + * {@link #doOnError(java.util.function.Consumer)}. + *

+ * Keep in mind that since the sequence can be asynchronous, this will immediately + * return control to the calling thread. This can give the impression the consumer is + * not invoked when executing in a main thread or a unit test for instance. + * + *

+ * + * + * @param consumer the consumer to invoke on each next signal + * @param errorConsumer the consumer to invoke on error signal + * + * @return a new {@link Disposable} that can be used to cancel the underlying {@link Subscription} + */ + public final Disposable subscribe(@Nullable Consumer consumer, Consumer errorConsumer) { + Objects.requireNonNull(errorConsumer, "errorConsumer"); + return subscribe(consumer, errorConsumer, null); + } + + /** + * Subscribe {@link Consumer} to this {@link Mono} that will respectively consume all the + * elements in the sequence, handle errors and react to completion. The subscription + * will request unbounded demand ({@code Long.MAX_VALUE}). + *

+ * For a passive version that observe and forward incoming data see {@link #doOnSuccess(Consumer)} and + * {@link #doOnError(java.util.function.Consumer)}. + *

+ * Keep in mind that since the sequence can be asynchronous, this will immediately + * return control to the calling thread. This can give the impression the consumer is + * not invoked when executing in a main thread or a unit test for instance. + * + *

+ * + * + * @param consumer the consumer to invoke on each value + * @param errorConsumer the consumer to invoke on error signal + * @param completeConsumer the consumer to invoke on complete signal + * + * @return a new {@link Disposable} that can be used to cancel the underlying {@link Subscription} + */ + public final Disposable subscribe( + @Nullable Consumer consumer, + @Nullable Consumer errorConsumer, + @Nullable Runnable completeConsumer) { + return subscribe(consumer, errorConsumer, completeConsumer, (Context) null); + } + + /** + * Subscribe {@link Consumer} to this {@link Mono} that will respectively consume all the + * elements in the sequence, handle errors, react to completion, and request upon subscription. + * It will let the provided {@link Subscription subscriptionConsumer} + * request the adequate amount of data, or request unbounded demand + * {@code Long.MAX_VALUE} if no such consumer is provided. + *

+ * For a passive version that observe and forward incoming data see {@link #doOnSuccess(Consumer)} and + * {@link #doOnError(java.util.function.Consumer)}. + *

+ * Keep in mind that since the sequence can be asynchronous, this will immediately + * return control to the calling thread. This can give the impression the consumer is + * not invoked when executing in a main thread or a unit test for instance. + * + *

+ * + * + * @param consumer the consumer to invoke on each value + * @param errorConsumer the consumer to invoke on error signal + * @param completeConsumer the consumer to invoke on complete signal + * @param subscriptionConsumer the consumer to invoke on subscribe signal, to be used + * for the initial {@link Subscription#request(long) request}, or null for max request + * + * @return a new {@link Disposable} that can be used to cancel the underlying {@link Subscription} + */ //TODO maybe deprecate in 3.4, provided there is at least an alternative for tests + public final Disposable subscribe( + @Nullable Consumer consumer, + @Nullable Consumer errorConsumer, + @Nullable Runnable completeConsumer, + @Nullable Consumer subscriptionConsumer) { + return subscribeWith(new LambdaMonoSubscriber<>(consumer, errorConsumer, + completeConsumer, subscriptionConsumer, null)); + } + + /** + * Subscribe {@link Consumer} to this {@link Mono} that will respectively consume all the + * elements in the sequence, handle errors and react to completion. Additionally, a {@link Context} + * is tied to the subscription. At subscription, an unbounded request is implicitly made. + *

+ * For a passive version that observe and forward incoming data see {@link #doOnSuccess(Consumer)} and + * {@link #doOnError(java.util.function.Consumer)}. + *

+ * Keep in mind that since the sequence can be asynchronous, this will immediately + * return control to the calling thread. This can give the impression the consumer is + * not invoked when executing in a main thread or a unit test for instance. + * + *

+ * + * + * @param consumer the consumer to invoke on each value + * @param errorConsumer the consumer to invoke on error signal + * @param completeConsumer the consumer to invoke on complete signal + * @param initialContext the {@link Context} for the subscription + * + * @return a new {@link Disposable} that can be used to cancel the underlying {@link Subscription} + */ + public final Disposable subscribe( + @Nullable Consumer consumer, + @Nullable Consumer errorConsumer, + @Nullable Runnable completeConsumer, + @Nullable Context initialContext) { + return subscribeWith(new LambdaMonoSubscriber<>(consumer, errorConsumer, + completeConsumer, null, initialContext)); + } + + @Override + @SuppressWarnings("unchecked") + public final void subscribe(Subscriber actual) { + CorePublisher publisher = Operators.onLastAssembly(this); + CoreSubscriber subscriber = Operators.toCoreSubscriber(actual); + + if (subscriber instanceof Fuseable.QueueSubscription && this != publisher && this instanceof Fuseable && !(publisher instanceof Fuseable)) { + subscriber = new FluxHide.SuppressFuseableSubscriber<>(subscriber); + } + + try { + if (publisher instanceof OptimizableOperator) { + OptimizableOperator operator = (OptimizableOperator) publisher; + while (true) { + subscriber = operator.subscribeOrReturn(subscriber); + if (subscriber == null) { + // null means "I will subscribe myself", returning... + return; + } + + OptimizableOperator newSource = operator.nextOptimizableSource(); + if (newSource == null) { + publisher = operator.source(); + break; + } + operator = newSource; + } + } + + publisher.subscribe(subscriber); + } + catch (Throwable e) { + Operators.reportThrowInSubscribe(subscriber, e); + return; + } + } + + /** + * An internal {@link Publisher#subscribe(Subscriber)} that will bypass + * {@link Hooks#onLastOperator(Function)} pointcut. + *

+ * In addition to behave as expected by {@link Publisher#subscribe(Subscriber)} + * in a controlled manner, it supports direct subscribe-time {@link Context} passing. + * + * @param actual the {@link Subscriber} interested into the published sequence + * @see Publisher#subscribe(Subscriber) + */ + public abstract void subscribe(CoreSubscriber actual); + + /** + * Run subscribe, onSubscribe and request on a specified {@link Scheduler}'s {@link Worker}. + * As such, placing this operator anywhere in the chain will also impact the execution + * context of onNext/onError/onComplete signals from the beginning of the chain up to + * the next occurrence of a {@link #publishOn(Scheduler) publishOn}. + *

+ * + * + *

+	 * {@code mono.subscribeOn(Schedulers.parallel()).subscribe()) }
+	 * 
+ * + * @param scheduler a {@link Scheduler} providing the {@link Worker} where to subscribe + * + * @return a {@link Mono} requesting asynchronously + * @see #publishOn(Scheduler) + */ + public final Mono subscribeOn(Scheduler scheduler) { + if(this instanceof Callable) { + if (this instanceof Fuseable.ScalarCallable) { + try { + T value = block(); + return onAssembly(new MonoSubscribeOnValue<>(value, scheduler)); + } + catch (Throwable t) { + //leave MonoSubscribeOnCallable defer error + } + } + @SuppressWarnings("unchecked") + Callable c = (Callable)this; + return onAssembly(new MonoSubscribeOnCallable<>(c, + scheduler)); + } + return onAssembly(new MonoSubscribeOn<>(this, scheduler)); + } + + /** + * Subscribe the given {@link Subscriber} to this {@link Mono} and return said + * {@link Subscriber}, allowing subclasses with a richer API to be used fluently. + * + * @param subscriber the {@link Subscriber} to subscribe with + * @param the reified type of the {@link Subscriber} for chaining + * + * @return the passed {@link Subscriber} after subscribing it to this {@link Mono} + */ + public final > E subscribeWith(E subscriber) { + subscribe(subscriber); + return subscriber; + } + + /** + * Fallback to an alternative {@link Mono} if this mono is completed without data + * + *

+ * + * + * @param alternate the alternate mono if this mono is empty + * + * @return a {@link Mono} falling back upon source completing without elements + * @see Flux#switchIfEmpty + */ + public final Mono switchIfEmpty(Mono alternate) { + return onAssembly(new MonoSwitchIfEmpty<>(this, alternate)); + } + + /** + * Tag this mono with a key/value pair. These can be retrieved as a {@link Set} of + * all tags throughout the publisher chain by using {@link Scannable#tags()} (as + * traversed by {@link Scannable#parents()}). + *

+ * The name is typically visible at assembly time by the {@link #tap(SignalListenerFactory)} operator, + * which could for example be configured with a metrics listener applying the tag(s) to its meters. + * + * @param key a tag key + * @param value a tag value + * + * @return the same sequence, but bearing tags + * + * @see #name(String) + * @see #metrics() + */ + public final Mono tag(String key, String value) { + return MonoName.createOrAppend(this, key, value); + } + + /** + * Give this Mono a chance to resolve within a specified time frame but complete if it + * doesn't. This works a bit like {@link #timeout(Duration)} except that the resulting + * {@link Mono} completes rather than errors when the timer expires. + *

+ * + *

+ * The timeframe is evaluated using the {@link Schedulers#parallel() parallel Scheduler}. + * + * @param duration the maximum duration to wait for the source Mono to resolve. + * @return a new {@link Mono} that will propagate the signals from the source unless + * no signal is received for {@code duration}, in which case it completes. + */ + public final Mono take(Duration duration) { + return take(duration, Schedulers.parallel()); + } + + /** + * Give this Mono a chance to resolve within a specified time frame but complete if it + * doesn't. This works a bit like {@link #timeout(Duration)} except that the resulting + * {@link Mono} completes rather than errors when the timer expires. + *

+ * + *

+ * The timeframe is evaluated using the provided {@link Scheduler}. + * + * @param duration the maximum duration to wait for the source Mono to resolve. + * @param timer the {@link Scheduler} on which to measure the duration. + * + * @return a new {@link Mono} that will propagate the signals from the source unless + * no signal is received for {@code duration}, in which case it completes. + */ + public final Mono take(Duration duration, Scheduler timer) { + return takeUntilOther(Mono.delay(duration, timer)); + } + + /** + * Give this Mono a chance to resolve before a companion {@link Publisher} emits. If + * the companion emits before any signal from the source, the resulting Mono will + * complete. Otherwise, it will relay signals from the source. + *

+ * + * + * @param other a companion {@link Publisher} that shortcircuits the source with an + * onComplete signal if it emits before the source emits. + * + * @return a new {@link Mono} that will propagate the signals from the source unless + * a signal is first received from the companion {@link Publisher}, in which case it + * completes. + */ + public final Mono takeUntilOther(Publisher other) { + return onAssembly(new MonoTakeUntilOther<>(this, other)); + } + + /** + * Tap into Reactive Streams signals emitted or received by this {@link Mono} and notify a stateful per-{@link Subscriber} + * {@link SignalListener}. + *

+ * Any exception thrown by the {@link SignalListener} methods causes the subscription to be cancelled + * and the subscriber to be terminated with an {@link Subscriber#onError(Throwable) onError signal} of that + * exception. Note that {@link SignalListener#doFinally(SignalType)}, {@link SignalListener#doAfterComplete()} and + * {@link SignalListener#doAfterError(Throwable)} instead just {@link Operators#onErrorDropped(Throwable, Context) drop} + * the exception. + *

+ * This simplified variant assumes the state is purely initialized within the {@link Supplier}, + * as it is called for each incoming {@link Subscriber} without additional context. + *

+ * When the context-propagation library + * is available at runtime and the downstream {@link ContextView} is not empty, this operator implicitly uses the library + * to restore thread locals around all invocations of {@link SignalListener} methods. Typically, this would be done + * in conjunction with the use of {@link #contextCapture()} operator down the chain. + * + * @param simpleListenerGenerator the {@link Supplier} to create a new {@link SignalListener} on each subscription + * @return a new {@link Mono} with side effects defined by generated {@link SignalListener} + * @see #tap(Function) + * @see #tap(SignalListenerFactory) + */ + public final Mono tap(Supplier> simpleListenerGenerator) { + return tap(new SignalListenerFactory() { + @Override + public Void initializePublisherState(Publisher ignored) { + return null; + } + + @Override + public SignalListener createListener(Publisher ignored1, ContextView ignored2, Void ignored3) { + return simpleListenerGenerator.get(); + } + }); + } + + /** + * Tap into Reactive Streams signals emitted or received by this {@link Mono} and notify a stateful per-{@link Subscriber} + * {@link SignalListener}. + *

+ * Any exception thrown by the {@link SignalListener} methods causes the subscription to be cancelled + * and the subscriber to be terminated with an {@link Subscriber#onError(Throwable) onError signal} of that + * exception. Note that {@link SignalListener#doFinally(SignalType)}, {@link SignalListener#doAfterComplete()} and + * {@link SignalListener#doAfterError(Throwable)} instead just {@link Operators#onErrorDropped(Throwable, Context) drop} + * the exception. + *

+ * This simplified variant allows the {@link SignalListener} to be constructed for each subscription + * with access to the incoming {@link Subscriber}'s {@link ContextView}. + *

+ * When the context-propagation library + * is available at runtime and the {@link ContextView} is not empty, this operator implicitly uses the library + * to restore thread locals around all invocations of {@link SignalListener} methods. Typically, this would be done + * in conjunction with the use of {@link #contextCapture()} operator down the chain. + * + * @param listenerGenerator the {@link Function} to create a new {@link SignalListener} on each subscription + * @return a new {@link Mono} with side effects defined by generated {@link SignalListener} + * @see #tap(Supplier) + * @see #tap(SignalListenerFactory) + */ + public final Mono tap(Function> listenerGenerator) { + return tap(new SignalListenerFactory() { + @Override + public Void initializePublisherState(Publisher ignored) { + return null; + } + + @Override + public SignalListener createListener(Publisher ignored1, ContextView listenerContext, Void ignored2) { + return listenerGenerator.apply(listenerContext); + } + }); + } + + /** + * Tap into Reactive Streams signals emitted or received by this {@link Mono} and notify a stateful per-{@link Subscriber} + * {@link SignalListener} created by the provided {@link SignalListenerFactory}. + *

+ * The factory will initialize a {@link SignalListenerFactory#initializePublisherState(Publisher) state object} for + * each {@link Flux} or {@link Mono} instance it is used with, and that state will be cached and exposed for each + * incoming {@link Subscriber} in order to generate the associated {@link SignalListenerFactory#createListener(Publisher, ContextView, Object) listener}. + *

+ * Any exception thrown by the {@link SignalListener} methods causes the subscription to be cancelled + * and the subscriber to be terminated with an {@link Subscriber#onError(Throwable) onError signal} of that + * exception. Note that {@link SignalListener#doFinally(SignalType)}, {@link SignalListener#doAfterComplete()} and + * {@link SignalListener#doAfterError(Throwable)} instead just {@link Operators#onErrorDropped(Throwable, Context) drop} + * the exception. + *

+ * When the context-propagation library + * is available at runtime and the downstream {@link ContextView} is not empty, this operator implicitly uses the library + * to restore thread locals around all invocations of {@link SignalListener} methods. Typically, this would be done + * in conjunction with the use of {@link #contextCapture()} operator down the chain. + * + * @param listenerFactory the {@link SignalListenerFactory} to create a new {@link SignalListener} on each subscription + * @return a new {@link Flux} with side effects defined by generated {@link SignalListener} + * @see #tap(Supplier) + * @see #tap(Function) + */ + public final Mono tap(SignalListenerFactory listenerFactory) { + if (this instanceof Fuseable) { + return onAssembly(new MonoTapFuseable<>(this, listenerFactory)); + } + return onAssembly(new MonoTap<>(this, listenerFactory)); + } + + /** + * Return a {@code Mono} which only replays complete and error signals + * from this {@link Mono}. + * + *

+ * + * + *

Discard Support: This operator discards the element from the source. + * + * @return a {@link Mono} ignoring its payload (actively dropping) + */ + public final Mono then() { + return empty(this); + } + + /** + * Let this {@link Mono} complete then play another Mono. + *

+ * In other words ignore element from this {@link Mono} and transform its completion signal into the + * emission and completion signal of a provided {@code Mono}. Error signal is + * replayed in the resulting {@code Mono}. + * + *

+ * + * + *

Discard Support: This operator discards the element from the source. + * + * @param other a {@link Mono} to emit from after termination + * @param the element type of the supplied Mono + * + * @return a new {@link Mono} that emits from the supplied {@link Mono} + */ + public final Mono then(Mono other) { + if (this instanceof MonoIgnoreThen) { + MonoIgnoreThen a = (MonoIgnoreThen) this; + return a.shift(other); + } + return onAssembly(new MonoIgnoreThen<>(new Publisher[] { this }, other)); + } + + /** + * Let this {@link Mono} complete successfully, then emit the provided value. On an error in the original {@link Mono}, the error signal is propagated instead. + *

+ * + * + *

Discard Support: This operator discards the element from the source. + * + * @param value a value to emit after successful termination + * @param the element type of the supplied value + * + * @return a new {@link Mono} that emits the supplied value + */ + public final Mono thenReturn(V value) { + return then(Mono.just(value)); + } + + /** + * Return a {@code Mono} that waits for this {@link Mono} to complete then + * for a supplied {@link Publisher Publisher<Void>} to also complete. The + * second completion signal is replayed, or any error signal that occurs instead. + *

+ * + * + *

Discard Support: This operator discards the element from the source. + * + * @param other a {@link Publisher} to wait for after this Mono's termination + * @return a new {@link Mono} completing when both publishers have completed in + * sequence + */ + public final Mono thenEmpty(Publisher other) { + return then(fromDirect(other)); + } + + /** + * Let this {@link Mono} complete successfully then play another {@link Publisher}. On an error in the original {@link Mono}, the error signal is propagated instead. + *

+ * In other words ignore the element from this mono and transform the completion signal into a + * {@code Flux} that will emit elements from the provided {@link Publisher}. + * + *

+ * + * + *

Discard Support: This operator discards the element from the source. + * + * @param other a {@link Publisher} to emit from after termination + * @param the element type of the supplied Publisher + * + * @return a new {@link Flux} that emits from the supplied {@link Publisher} after + * this Mono completes. + */ + public final Flux thenMany(Publisher other) { + @SuppressWarnings("unchecked") + Flux concat = (Flux)Flux.concat(ignoreElement(), other); + return Flux.onAssembly(concat); + } + + + /** + * Times this {@link Mono} {@link Subscriber#onNext(Object)} event, encapsulated into a {@link Timed} object + * that lets downstream consumer look at various time information gathered with nanosecond + * resolution using the default clock ({@link Schedulers#parallel()}): + *

    + *
  • {@link Timed#elapsed()}: the time in nanoseconds since subscription, as a {@link Duration}. + * This is functionally equivalent to {@link #elapsed()}, with a more expressive and precise + * representation than a {@link Tuple2} with a long.
  • + *
  • {@link Timed#timestamp()}: the timestamp of this onNext, as an {@link java.time.Instant} + * (with nanoseconds part). This is functionally equivalent to {@link #timestamp()}, with a more + * expressive and precise representation than a {@link Tuple2} with a long.
  • + *
  • {@link Timed#elapsedSinceSubscription()}: for {@link Mono} this is the same as + * {@link Timed#elapsed()}.
  • + *
+ *

+ * The {@link Timed} object instances are safe to store and use later, as they are created as an + * immutable wrapper around the {@code } value and immediately passed downstream. + *

+ * + * + * @return a timed {@link Mono} + * @see #elapsed() + * @see #timestamp() + */ + public final Mono> timed() { + return this.timed(Schedulers.parallel()); + } + + /** + * Times this {@link Mono} {@link Subscriber#onNext(Object)} event, encapsulated into a {@link Timed} object + * that lets downstream consumer look at various time information gathered with nanosecond + * resolution using the provided {@link Scheduler} as a clock: + *

    + *
  • {@link Timed#elapsed()}: the time in nanoseconds since subscription, as a {@link Duration}. + * This is functionally equivalent to {@link #elapsed()}, with a more expressive and precise + * representation than a {@link Tuple2} with a long.
  • + *
  • {@link Timed#timestamp()}: the timestamp of this onNext, as an {@link java.time.Instant} + * (with nanoseconds part). This is functionally equivalent to {@link #timestamp()}, with a more + * expressive and precise representation than a {@link Tuple2} with a long.
  • + *
  • {@link Timed#elapsedSinceSubscription()}: for {@link Mono} this is the same as + * {@link Timed#elapsed()}.
  • + *
+ *

+ * The {@link Timed} object instances are safe to store and use later, as they are created as an + * immutable wrapper around the {@code } value and immediately passed downstream. + *

+ * + * + * @return a timed {@link Mono} + * @see #elapsed(Scheduler) + * @see #timestamp(Scheduler) + */ + public final Mono> timed(Scheduler clock) { + return onAssembly(new MonoTimed<>(this, clock)); + } + + /** + * Propagate a {@link TimeoutException} in case no item arrives within the given + * {@link Duration}. + * + *

+ * + * + * @param timeout the timeout before the onNext signal from this {@link Mono} + * + * @return a {@link Mono} that can time out + */ + public final Mono timeout(Duration timeout) { + return timeout(timeout, Schedulers.parallel()); + } + + /** + * Switch to a fallback {@link Mono} in case no item arrives within the given {@link Duration}. + * + *

+ * If the fallback {@link Mono} is null, signal a {@link TimeoutException} instead. + * + *

+ * + * + * @param timeout the timeout before the onNext signal from this {@link Mono} + * @param fallback the fallback {@link Mono} to subscribe to when a timeout occurs + * + * @return a {@link Mono} that will fallback to a different {@link Mono} in case of timeout + */ + public final Mono timeout(Duration timeout, Mono fallback) { + return timeout(timeout, fallback, Schedulers.parallel()); + } + + /** + * Signal a {@link TimeoutException} error in case an item doesn't arrive before the given period, + * as measured on the provided {@link Scheduler}. + * + *

+ * + * + * @param timeout the timeout before the onNext signal from this {@link Mono} + * @param timer a time-capable {@link Scheduler} instance to run the delay on + * + * @return an expirable {@link Mono} + */ + public final Mono timeout(Duration timeout, Scheduler timer) { + return timeout(timeout, null, timer); + } + + /** + * Switch to a fallback {@link Mono} in case an item doesn't arrive before the given period, + * as measured on the provided {@link Scheduler}. + * + *

If the given {@link Mono} is null, signal a {@link TimeoutException}. + * + *

+ * + * + * @param timeout the timeout before the onNext signal from this {@link Mono} + * @param fallback the fallback {@link Mono} to subscribe when a timeout occurs + * @param timer a time-capable {@link Scheduler} instance to run on + * + * @return an expirable {@link Mono} with a fallback {@link Mono} + */ + public final Mono timeout(Duration timeout, @Nullable Mono fallback, + Scheduler timer) { + final Mono _timer = Mono.delay(timeout, timer).onErrorReturn(0L); + + if(fallback == null) { + return onAssembly(new MonoTimeout<>(this, _timer, timeout.toMillis() + "ms")); + } + return onAssembly(new MonoTimeout<>(this, _timer, fallback)); + } + + /** + * Signal a {@link TimeoutException} in case the item from this {@link Mono} has + * not been emitted before the given {@link Publisher} emits. + * + *

+ * + * + * @param firstTimeout the timeout {@link Publisher} that must not emit before the first signal from this {@link Mono} + * @param the element type of the timeout Publisher + * + * @return an expirable {@link Mono} if the item does not come before a {@link Publisher} signals + * + */ + public final Mono timeout(Publisher firstTimeout) { + return onAssembly(new MonoTimeout<>(this, firstTimeout, "first signal from a Publisher")); + } + + /** + * Switch to a fallback {@link Publisher} in case the item from this {@link Mono} has + * not been emitted before the given {@link Publisher} emits. + * + *

+ * + * + * @param firstTimeout the timeout + * {@link Publisher} that must not emit before the first signal from this {@link Mono} + * @param fallback the fallback {@link Publisher} to subscribe when a timeout occurs + * @param the element type of the timeout Publisher + * + * @return an expirable {@link Mono} with a fallback {@link Mono} if the item doesn't + * come before a {@link Publisher} signals + * + */ + public final Mono timeout(Publisher firstTimeout, Mono fallback) { + return onAssembly(new MonoTimeout<>(this, firstTimeout, fallback)); + } + + /** + * If this {@link Mono} is valued, emit a {@link reactor.util.function.Tuple2} pair of + * T1 the current clock time in millis (as a {@link Long} measured by the + * {@link Schedulers#parallel() parallel} Scheduler) and T2 the emitted data (as a {@code T}). + * + *

+ * + * + * @return a timestamped {@link Mono} + * @see #timed() + */ + public final Mono> timestamp() { + return timestamp(Schedulers.parallel()); + } + + /** + * If this {@link Mono} is valued, emit a {@link reactor.util.function.Tuple2} pair of + * T1 the current clock time in millis (as a {@link Long} measured by the + * provided {@link Scheduler}) and T2 the emitted data (as a {@code T}). + * + *

The provider {@link Scheduler} will be asked to {@link Scheduler#now(TimeUnit) provide time} + * with a granularity of {@link TimeUnit#MILLISECONDS}. In order for this operator to work as advertised, the + * provided Scheduler should thus return results that can be interpreted as unix timestamps.

+ *

+ * + * + * + * @param scheduler a {@link Scheduler} instance to read time from + * @return a timestamped {@link Mono} + * @see Scheduler#now(TimeUnit) + * @see #timed(Scheduler) + */ + public final Mono> timestamp(Scheduler scheduler) { + Objects.requireNonNull(scheduler, "scheduler"); + return map(d -> Tuples.of(scheduler.now(TimeUnit.MILLISECONDS), d)); + } + + /** + * Transform this {@link Mono} into a {@link CompletableFuture} completing on onNext or onComplete and failing on + * onError. + * + *

+ * + * + * @return a {@link CompletableFuture} + */ + public final CompletableFuture toFuture() { + return subscribeWith(new MonoToCompletableFuture<>(false)); + } + + /** + * Transform this {@link Mono} in order to generate a target {@link Mono}. Unlike {@link #transformDeferred(Function)}, the + * provided function is executed as part of assembly. + * + *

+	 * Function applySchedulers = mono -> mono.subscribeOn(Schedulers.io())
+	 *                                                    .publishOn(Schedulers.parallel());
+	 * mono.transform(applySchedulers).map(v -> v * v).subscribe();
+	 * 
+ *

+ * + * + * @param transformer the {@link Function} to immediately map this {@link Mono} into a target {@link Mono} + * instance. + * @param the item type in the returned {@link Mono} + * + * @return a new {@link Mono} + * @see #transformDeferred(Function) transformDeferred(Function) for deferred composition of Mono for each Subscriber + * @see #as(Function) as(Function) for a loose conversion to an arbitrary type + */ + @SuppressWarnings({"unchecked", "rawtypes"}) + public final Mono transform(Function, ? extends Publisher> transformer) { + if (Hooks.DETECT_CONTEXT_LOSS) { + transformer = new ContextTrackingFunctionWrapper(transformer); + } + return onAssembly(from(transformer.apply(this))); + } + + /** + * Defer the given transformation to this {@link Mono} in order to generate a + * target {@link Mono} type. A transformation will occur for each + * {@link Subscriber}. For instance: + * + *

+	 * mono.transformDeferred(original -> original.log());
+	 * 
+ *

+ * + * + * @param transformer the {@link Function} to lazily map this {@link Mono} into a target {@link Mono} + * instance upon subscription. + * @param the item type in the returned {@link Publisher} + * + * @return a new {@link Mono} + * @see #transform(Function) transform(Function) for immmediate transformation of Mono + * @see #transformDeferredContextual(BiFunction) transformDeferredContextual(BiFunction) for a similarly deferred transformation of Mono reading the ContextView + * @see #as(Function) as(Function) for a loose conversion to an arbitrary type + */ + public final Mono transformDeferred(Function, ? extends Publisher> transformer) { + return defer(() -> { + if (Hooks.DETECT_CONTEXT_LOSS) { + @SuppressWarnings({"unchecked", "rawtypes"}) + Mono result = from(new ContextTrackingFunctionWrapper((Function) transformer).apply(this)); + return result; + } + return from(transformer.apply(this)); + }); + } + + /** + * Defer the given transformation to this {@link Mono} in order to generate a + * target {@link Mono} type. A transformation will occur for each + * {@link Subscriber}. In addition, the transforming {@link BiFunction} exposes + * the {@link ContextView} of each {@link Subscriber}. For instance: + * + *

+	 * Mono<T> monoLogged = mono.transformDeferredContextual((original, ctx) -> original.log("for RequestID" + ctx.get("RequestID"))
+	 * //...later subscribe. Each subscriber has its Context with a RequestID entry
+	 * monoLogged.contextWrite(Context.of("RequestID", "requestA").subscribe();
+	 * monoLogged.contextWrite(Context.of("RequestID", "requestB").subscribe();
+	 * 
+ *

+ * + * + * @param transformer the {@link BiFunction} to lazily map this {@link Mono} into a target {@link Mono} + * instance upon subscription, with access to {@link ContextView} + * @param the item type in the returned {@link Publisher} + * @return a new {@link Mono} + * @see #transform(Function) transform(Function) for immmediate transformation of Mono + * @see #transformDeferred(Function) transformDeferred(Function) for a similarly deferred transformation of Mono without the ContextView + * @see #as(Function) as(Function) for a loose conversion to an arbitrary type + */ + public final Mono transformDeferredContextual(BiFunction, ? super ContextView, ? extends Publisher> transformer) { + return deferContextual(ctxView -> { + if (Hooks.DETECT_CONTEXT_LOSS) { + ContextTrackingFunctionWrapper wrapper = new ContextTrackingFunctionWrapper<>( + publisher -> transformer.apply(wrap(publisher, false), ctxView), + transformer.toString() + ); + return wrap(wrapper.apply(this), true); + } + return from(transformer.apply(this, ctxView)); + }); + } + + /** + * Wait for the result from this mono, use it to create a second mono via the + * provided {@code rightGenerator} function and combine both results into a {@link Tuple2}. + * + *

+ * + * + * @param rightGenerator the {@link Function} to generate a {@code Mono} to combine with + * @param the element type of the other Mono instance + * + * @return a new combined Mono + */ + public final Mono> zipWhen(Function> rightGenerator) { + return zipWhen(rightGenerator, Tuples::of); + } + + /** + * Wait for the result from this mono, use it to create a second mono via the + * provided {@code rightGenerator} function and combine both results into an arbitrary + * {@code O} object, as defined by the provided {@code combinator} function. + * + *

+ * + * + * @param rightGenerator the {@link Function} to generate a {@code Mono} to combine with + * @param combinator a {@link BiFunction} combinator function when both sources complete + * @param the element type of the other Mono instance + * @param the element type of the combination + * + * @return a new combined Mono + */ + public final Mono zipWhen(Function> rightGenerator, + BiFunction combinator) { + Objects.requireNonNull(rightGenerator, "rightGenerator function is mandatory to get the right-hand side Mono"); + Objects.requireNonNull(combinator, "combinator function is mandatory to combine results from both Monos"); + return flatMap(t -> rightGenerator.apply(t).map(t2 -> combinator.apply(t, t2))); + } + + /** + * Combine the result from this mono and another into a {@link Tuple2}. + *

+ * An error or empty completion of any source will cause the other source + * to be cancelled and the resulting Mono to immediately error or complete, respectively. + * + *

+ * + * + * @param other the {@link Mono} to combine with + * @param the element type of the other Mono instance + * + * @return a new combined Mono + */ + public final Mono> zipWith(Mono other) { + return zipWith(other, Flux.tuple2Function()); + } + + /** + * Combine the result from this mono and another into an arbitrary {@code O} object, + * as defined by the provided {@code combinator} function. + *

+ * An error or empty completion of any source will cause the other source + * to be cancelled and the resulting Mono to immediately error or complete, respectively. + * + *

+ * + * + * @param other the {@link Mono} to combine with + * @param combinator a {@link BiFunction} combinator function when both sources + * complete + * @param the element type of the other Mono instance + * @param the element type of the combination + * + * @return a new combined Mono + */ + public final Mono zipWith(Mono other, + BiFunction combinator) { + if (this instanceof MonoZip) { + @SuppressWarnings("unchecked") MonoZip o = (MonoZip) this; + Mono result = o.zipAdditionalSource(other, combinator); + if (result != null) { + return result; + } + } + + return zip(this, other, combinator); + } + + /** + * To be used by custom operators: invokes assembly {@link Hooks} pointcut given a + * {@link Mono}, potentially returning a new {@link Mono}. This is for example useful + * to activate cross-cutting concerns at assembly time, eg. a generalized + * {@link #checkpoint()}. + * + * @param the value type + * @param source the source to apply assembly hooks onto + * + * @return the source, potentially wrapped with assembly time cross-cutting behavior + */ + @SuppressWarnings("unchecked") + protected static Mono onAssembly(Mono source) { + Function hook = Hooks.onEachOperatorHook; + if(hook != null) { + source = (Mono) hook.apply(source); + } + if (Hooks.GLOBAL_TRACE) { + AssemblySnapshot stacktrace = new AssemblySnapshot(null, Traces.callSiteSupplierFactory.get()); + source = (Mono) Hooks.addAssemblyInfo(source, stacktrace); + } + return source; + } + + @Override + public String toString() { + return getClass().getSimpleName(); + } + + + static Mono empty(Publisher source) { + @SuppressWarnings("unchecked") + Mono then = (Mono)ignoreElements(source); + return then; + } + + static Mono doOnSignal(Mono source, + @Nullable Consumer onSubscribe, + @Nullable Consumer onNext, + @Nullable LongConsumer onRequest, + @Nullable Runnable onCancel) { + if (source instanceof Fuseable) { + return onAssembly(new MonoPeekFuseable<>(source, + onSubscribe, + onNext, + onRequest, + onCancel)); + } + return onAssembly(new MonoPeek<>(source, + onSubscribe, + onNext, + onRequest, + onCancel)); + } + + static Mono doOnTerminalSignal(Mono source, + @Nullable Consumer onSuccess, + @Nullable Consumer onError, + @Nullable BiConsumer onAfterTerminate) { + return onAssembly(new MonoPeekTerminal<>(source, onSuccess, onError, onAfterTerminate)); + } + + /** + * Unchecked wrap of {@link Publisher} as {@link Mono}, supporting {@link Fuseable} sources. + * When converting a {@link Mono} or {@link Mono Monos} that have been converted to a {@link Flux} and back, + * the original {@link Mono} is returned unwrapped. + * Note that this bypasses {@link Hooks#onEachOperator(String, Function) assembly hooks}. + * + * @param source the {@link Publisher} to wrap + * @param enforceMonoContract {@code} true to wrap publishers without assumption about their cardinality + * (first {@link Subscriber#onNext(Object)} will cancel the source), {@code false} to behave like {@link #fromDirect(Publisher)}. + * @param input upstream type + * @return a wrapped {@link Mono} + */ + static Mono wrap(Publisher source, boolean enforceMonoContract) { + //some sources can be considered already assembled monos + //all conversion methods (from, fromDirect, wrap) must accommodate for this + if (source instanceof Mono) { + return (Mono) source; + } + if (source instanceof FluxSourceMono + || source instanceof FluxSourceMonoFuseable) { + @SuppressWarnings("unchecked") + Mono extracted = (Mono) ((FluxFromMonoOperator) source).source; + return extracted; + } + + //equivalent to what from used to be, without assembly hooks + if (enforceMonoContract) { + if (source instanceof Flux && source instanceof Callable) { + @SuppressWarnings("unchecked") Callable m = (Callable) source; + return Flux.wrapToMono(m); + } + if (source instanceof Flux) { + return new MonoNext<>((Flux) source); + } + return new MonoFromPublisher<>(source); + } + + //equivalent to what fromDirect used to be without onAssembly + if(source instanceof Flux && source instanceof Fuseable) { + return new MonoSourceFluxFuseable<>((Flux) source); + } + if (source instanceof Flux) { + return new MonoSourceFlux<>((Flux) source); + } + if(source instanceof Fuseable) { + return new MonoSourceFuseable<>(source); + } + return new MonoSource<>(source); + } + + @SuppressWarnings("unchecked") + static BiPredicate equalsBiPredicate(){ + return EQUALS_BIPREDICATE; + } + static final BiPredicate EQUALS_BIPREDICATE = Object::equals; +} diff --git a/reactor-core/src/main/java/reactor/core/publisher/MonoSingleOptional.java b/reactor-core/src/main/java/reactor/core/publisher/MonoSingleOptional.java index 159c5d6288..5a0cd8857d 100644 --- a/reactor-core/src/main/java/reactor/core/publisher/MonoSingleOptional.java +++ b/reactor-core/src/main/java/reactor/core/publisher/MonoSingleOptional.java @@ -1,157 +1,148 @@ -/* - * Copyright (c) 2016-2021 VMware Inc. or its affiliates, All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package reactor.core.publisher; - -import java.util.Optional; - -import org.reactivestreams.Subscription; - -import reactor.core.CoreSubscriber; -import reactor.util.annotation.Nullable; -import reactor.util.context.Context; - -/** - * Expects and emits a single item from the source wrapped into an Optional, emits - * an empty Optional instead for empty source or signals - * IndexOutOfBoundsException for a multi-item source. - * - * @param the value type - * @see Reactive-Streams-Commons - */ -/** - * Wraps the item from the source into an Optional, emits - * an empty Optional instead for empty source or signals - * IndexOutOfBoundsException for a multi-item source. - * - * @param the value type - * @see Reactive-Streams-Commons - */ -final class MonoSingleOptional extends InternalMonoOperator> { - - MonoSingleOptional(Mono source) { - super(source); - } - - @Override - public CoreSubscriber subscribeOrReturn(CoreSubscriber> actual) { - return new MonoSingleOptional.SingleOptionalSubscriber<>(actual); - } - - @Override - public Object scanUnsafe(Attr key) { - if (key == Attr.RUN_STYLE) return Attr.RunStyle.SYNC; - return super.scanUnsafe(key); - } - - static final class SingleOptionalSubscriber extends Operators.MonoInnerProducerBase> implements InnerConsumer { - - Subscription s; - - int count; - - boolean done; - - @Override - @Nullable - public Object scanUnsafe(Attr key) { - if (key == Attr.TERMINATED) return done; - if (key == Attr.PARENT) return s; - if (key == Attr.RUN_STYLE) return Attr.RunStyle.SYNC; - - return super.scanUnsafe(key); - } - - @Override - public Context currentContext() { - return actual().currentContext(); - } - - SingleOptionalSubscriber(CoreSubscriber> actual) { - super(actual); - } - - @Override - public void doOnRequest(long n) { - s.request(Long.MAX_VALUE); - } - - @Override - public void doOnCancel() { - s.cancel(); - } - - @Override - public void onSubscribe(Subscription s) { - if (Operators.validate(this.s, s)) { - this.s = s; - actual().onSubscribe(this); - } - } - - @Override - public void onNext(T t) { - if (isCancelled()) { - //this helps differentiating a duplicate malformed signal "done" from a count > 1 "done" - Operators.onDiscard(t, actual().currentContext()); - return; - } - if (done) { - Operators.onNextDropped(t, actual().currentContext()); - return; - } - if (++count > 1) { - Operators.onDiscard(t, actual().currentContext()); - //mark as both cancelled and done - cancel(); - onError(new IndexOutOfBoundsException("Source emitted more than one item")); - } - else { - setValue(Optional.of(t)); - } - } - - @Override - public void onError(Throwable t) { - if (done) { - Operators.onErrorDropped(t, actual().currentContext()); - return; - } - done = true; - discardTheValue(); - - actual().onError(t); - } - - @Override - public void onComplete() { - if (done) { - return; - } - done = true; - - int c = count; - if (c == 0) { - - complete(Optional.empty()); - } - else if (c == 1) { - complete(); - } - } - - } -} +/* + * Copyright (c) 2016-2023 VMware Inc. or its affiliates, All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package reactor.core.publisher; + +import java.util.Optional; + +import org.reactivestreams.Subscription; + +import reactor.core.CoreSubscriber; +import reactor.util.annotation.Nullable; +import reactor.util.context.Context; + +/** + * Expects and emits a single item from the source wrapped into an Optional, emits + * an empty Optional instead for empty source or signals + * IndexOutOfBoundsException for a multi-item source. + * + * @param the value type + * @see Reactive-Streams-Commons + */ +final class MonoSingleOptional extends InternalMonoOperator> { + + MonoSingleOptional(Mono source) { + super(source); + } + + @Override + public CoreSubscriber subscribeOrReturn(CoreSubscriber> actual) { + return new MonoSingleOptional.SingleOptionalSubscriber<>(actual); + } + + @Override + public Object scanUnsafe(Attr key) { + if (key == Attr.RUN_STYLE) return Attr.RunStyle.SYNC; + return super.scanUnsafe(key); + } + + static final class SingleOptionalSubscriber extends Operators.MonoInnerProducerBase> implements InnerConsumer { + + Subscription s; + + int count; + + boolean done; + + @Override + @Nullable + public Object scanUnsafe(Attr key) { + if (key == Attr.TERMINATED) return done; + if (key == Attr.PARENT) return s; + if (key == Attr.RUN_STYLE) return Attr.RunStyle.SYNC; + + return super.scanUnsafe(key); + } + + @Override + public Context currentContext() { + return actual().currentContext(); + } + + SingleOptionalSubscriber(CoreSubscriber> actual) { + super(actual); + } + + @Override + public void doOnRequest(long n) { + s.request(Long.MAX_VALUE); + } + + @Override + public void doOnCancel() { + s.cancel(); + } + + @Override + public void onSubscribe(Subscription s) { + if (Operators.validate(this.s, s)) { + this.s = s; + actual().onSubscribe(this); + } + } + + @Override + public void onNext(T t) { + if (isCancelled()) { + //this helps differentiating a duplicate malformed signal "done" from a count > 1 "done" + Operators.onDiscard(t, actual().currentContext()); + return; + } + if (done) { + Operators.onNextDropped(t, actual().currentContext()); + return; + } + if (++count > 1) { + Operators.onDiscard(t, actual().currentContext()); + //mark as both cancelled and done + cancel(); + onError(new IndexOutOfBoundsException("Source emitted more than one item")); + } + else { + setValue(Optional.of(t)); + } + } + + @Override + public void onError(Throwable t) { + if (done) { + Operators.onErrorDropped(t, actual().currentContext()); + return; + } + done = true; + discardTheValue(); + + actual().onError(t); + } + + @Override + public void onComplete() { + if (done) { + return; + } + done = true; + + int c = count; + if (c == 0) { + complete(Optional.empty()); + } + else if (c == 1) { + complete(); + } + } + + } +} diff --git a/reactor-core/src/main/java/reactor/core/publisher/MonoSingleOptionalCallable.java b/reactor-core/src/main/java/reactor/core/publisher/MonoSingleOptionalCallable.java index 26d1ed649a..6226487212 100644 --- a/reactor-core/src/main/java/reactor/core/publisher/MonoSingleOptionalCallable.java +++ b/reactor-core/src/main/java/reactor/core/publisher/MonoSingleOptionalCallable.java @@ -1,98 +1,98 @@ -/* - * Copyright (c) 2016-2021 VMware Inc. or its affiliates, All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package reactor.core.publisher; - -import reactor.core.CoreSubscriber; -import reactor.core.Exceptions; -import reactor.util.annotation.Nullable; - -import java.time.Duration; -import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.Callable; - -/** - * Expects and emits a single item from the source Callable and warps it into an Optional, - * emits an empty Optional for empty source. - * - * @param the value type - * @see Reactive-Streams-Commons - */ -final class MonoSingleOptionalCallable extends Mono> - implements Callable>, SourceProducer> { - - final Callable callable; - - MonoSingleOptionalCallable(Callable source) { - this.callable = Objects.requireNonNull(source, "source"); - } - - @Override - public void subscribe(CoreSubscriber> actual) { - Operators.MonoInnerProducerBase> - sds = new Operators.MonoInnerProducerBase<>(actual); - - actual.onSubscribe(sds); - - if (sds.isCancelled()) { - return; - } - - try { - T t = callable.call(); - sds.complete(Optional.ofNullable(t)); - } - catch (Throwable e) { - actual.onError(Operators.onOperatorError(e, actual.currentContext())); - } - - } - - @Override - public Optional block() { - //duration is ignored below - return block(Duration.ZERO); - } - - @Override - public Optional block(Duration m) { - final T v; - - try { - v = callable.call(); - } - catch (Throwable e) { - throw Exceptions.propagate(e); - } - - return Optional.ofNullable(v); - } - - @Override - public Optional call() throws Exception { - final T v = callable.call(); - - return Optional.ofNullable(v); - } - - @Override - public Object scanUnsafe(Attr key) { - if (key == Attr.RUN_STYLE) return Attr.RunStyle.SYNC; - return null; - } -} +/* + * Copyright (c) 2016-2023 VMware Inc. or its affiliates, All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package reactor.core.publisher; + +import reactor.core.CoreSubscriber; +import reactor.core.Exceptions; +import reactor.util.annotation.Nullable; + +import java.time.Duration; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.Callable; + +/** + * Expects and emits a single item from the source Callable and warps it into an Optional, + * emits an empty Optional for empty source. + * + * @param the value type + * @see Reactive-Streams-Commons + */ +final class MonoSingleOptionalCallable extends Mono> + implements Callable>, SourceProducer> { + + final Callable callable; + + MonoSingleOptionalCallable(Callable source) { + this.callable = Objects.requireNonNull(source, "source"); + } + + @Override + public void subscribe(CoreSubscriber> actual) { + Operators.MonoInnerProducerBase> + sds = new Operators.MonoInnerProducerBase<>(actual); + + actual.onSubscribe(sds); + + if (sds.isCancelled()) { + return; + } + + try { + T t = callable.call(); + sds.complete(Optional.ofNullable(t)); + } + catch (Throwable e) { + actual.onError(Operators.onOperatorError(e, actual.currentContext())); + } + + } + + @Override + public Optional block() { + //duration is ignored below + return block(Duration.ZERO); + } + + @Override + public Optional block(Duration m) { + final T v; + + try { + v = callable.call(); + } + catch (Throwable e) { + throw Exceptions.propagate(e); + } + + return Optional.ofNullable(v); + } + + @Override + public Optional call() throws Exception { + final T v = callable.call(); + + return Optional.ofNullable(v); + } + + @Override + public Object scanUnsafe(Attr key) { + if (key == Attr.RUN_STYLE) return Attr.RunStyle.SYNC; + return null; + } +} diff --git a/reactor-core/src/test/java/reactor/core/publisher/MonoSingleMonoTest.java b/reactor-core/src/test/java/reactor/core/publisher/MonoSingleMonoTest.java index d443972a6a..b74aa7536b 100644 --- a/reactor-core/src/test/java/reactor/core/publisher/MonoSingleMonoTest.java +++ b/reactor-core/src/test/java/reactor/core/publisher/MonoSingleMonoTest.java @@ -1,87 +1,98 @@ -/* - * Copyright (c) 2017-2021 VMware Inc. or its affiliates, All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package reactor.core.publisher; - -import java.util.NoSuchElementException; -import java.util.function.Function; - -import org.junit.jupiter.api.Test; - -import reactor.core.Fuseable; -import reactor.core.Scannable; -import reactor.test.StepVerifier; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; - -public class MonoSingleMonoTest { - - @Test - public void callableEmpty() { - StepVerifier.create(Mono.empty().single()) - .verifyErrorSatisfies(e -> assertThat(e) - .isInstanceOf(NoSuchElementException.class) - .hasMessage("Source was a (constant) empty")); - } - - @Test - public void callableValued() { - StepVerifier.create(Mono.just("foo").single()) - .expectNext("foo") - .verifyComplete(); - } - - @Test - public void normalEmpty() { - StepVerifier.create(Mono.empty().hide().single()) - .verifyErrorSatisfies(e -> assertThat(e) - .isInstanceOf(NoSuchElementException.class) - .hasMessage("Source was empty")); - } - - @Test - public void normalValued() { - StepVerifier.create(Mono.just("foo").hide().single()) - .expectNext("foo") - .verifyComplete(); - } - - // see https://github.com/reactor/reactor-core/issues/2663 - @Test - void fusionMonoSingleMonoDoesntTriggerFusion() { - Mono fusedCase = Mono - .just(1) - .map(Function.identity()) - .single(); - - assertThat(fusedCase) - .as("fusedCase assembly check") - .isInstanceOf(MonoSingleMono.class) - .isNotInstanceOf(Fuseable.class); - - assertThatCode(() -> fusedCase.filter(v -> true).block()) - .as("fusedCase fused") - .doesNotThrowAnyException(); - } - - @Test - public void scanOperator(){ - MonoSingleMono test = new MonoSingleMono<>(Mono.just("foo")); - - assertThat(test.scan(Scannable.Attr.RUN_STYLE)).isSameAs(Scannable.Attr.RunStyle.SYNC); - } -} +/* + * Copyright (c) 2017-2023 VMware Inc. or its affiliates, All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package reactor.core.publisher; + +import java.util.NoSuchElementException; +import java.util.function.Function; + +import org.junit.jupiter.api.Test; + +import reactor.core.Fuseable; +import reactor.core.Scannable; +import reactor.test.StepVerifier; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; + +public class MonoSingleMonoTest { + + @Test + public void callableEmpty() { + StepVerifier.create(Mono.empty().single()) + .verifyErrorSatisfies(e -> assertThat(e) + .isInstanceOf(NoSuchElementException.class) + .hasMessage("Source was a (constant) empty")); + } + + @Test + public void callableValued() { + StepVerifier.create(Mono.just("foo").single()) + .expectNext("foo") + .verifyComplete(); + } + + @Test + public void callableError() { + StepVerifier.create(Mono.error(new IllegalStateException("failed")).single()) + .expectErrorMessage("failed"); + } + + @Test + public void normalEmpty() { + StepVerifier.create(Mono.empty().hide().single()) + .verifyErrorSatisfies(e -> assertThat(e) + .isInstanceOf(NoSuchElementException.class) + .hasMessage("Source was empty")); + } + + @Test + public void normalValued() { + StepVerifier.create(Mono.just("foo").hide().single()) + .expectNext("foo") + .verifyComplete(); + } + + @Test + public void normalError() { + StepVerifier.create(Mono.error(new IllegalStateException("failed")).hide().single()) + .expectErrorMessage("failed"); + } + // see https://github.com/reactor/reactor-core/issues/2663 + @Test + void fusionMonoSingleMonoDoesntTriggerFusion() { + Mono fusedCase = Mono + .just(1) + .map(Function.identity()) + .single(); + + assertThat(fusedCase) + .as("fusedCase assembly check") + .isInstanceOf(MonoSingleMono.class) + .isNotInstanceOf(Fuseable.class); + + assertThatCode(() -> fusedCase.filter(v -> true).block()) + .as("fusedCase fused") + .doesNotThrowAnyException(); + } + + @Test + public void scanOperator(){ + MonoSingleMono test = new MonoSingleMono<>(Mono.just("foo")); + + assertThat(test.scan(Scannable.Attr.RUN_STYLE)).isSameAs(Scannable.Attr.RunStyle.SYNC); + } +} diff --git a/reactor-core/src/test/java/reactor/core/publisher/MonoSingleOptionalCallableTest.java b/reactor-core/src/test/java/reactor/core/publisher/MonoSingleOptionalCallableTest.java new file mode 100644 index 0000000000..dd657c3f0f --- /dev/null +++ b/reactor-core/src/test/java/reactor/core/publisher/MonoSingleOptionalCallableTest.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2021-2023 VMware Inc. or its affiliates, All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package reactor.core.publisher; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.time.Duration; +import java.util.Optional; +import java.util.concurrent.Callable; + +import org.junit.jupiter.api.Test; + +import reactor.core.Fuseable; +import reactor.core.Scannable; +import reactor.test.StepVerifier; + +class MonoSingleOptionalCallableTest { + + @Test + void testCallableFusedEmptySource() { + Mono> mono = Mono + .fromSupplier(() -> null) + .singleOptional(); + + StepVerifier.create(mono) + .expectNext(Optional.empty()) + .verifyComplete(); + } + + @Test + void testCallableFusedSingleEmptySourceOnBlock() { + Mono> mono = Mono + .fromSupplier(() -> null) + .singleOptional(); + + assertEquals(Optional.empty(), mono.block()); + } + + @Test + void testCallableFusedSingleEmptySourceOnCall() throws Exception { + Mono> mono = Mono + .fromSupplier(() -> null) + .singleOptional(); + + assertThat(mono).isInstanceOf(MonoSingleOptionalCallable.class); + + assertEquals(Optional.empty(), ((Callable) mono).call()); + } + + @Test + void sourceNull() { + assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> { + new MonoSingleOptionalCallable<>(null); + }); + } + + @Test + void normal() { + StepVerifier.create(new MonoSingleOptionalCallable<>(() -> 1)) + .expectNext(Optional.of(1)) + .verifyComplete(); + } + + @Test + void normalBackpressured() { + StepVerifier.create(new MonoSingleOptionalCallable<>(() -> 1), 0) + .expectSubscription() + .expectNoEvent(Duration.ofMillis(50)) + .thenRequest(1) + .expectNext(Optional.of(1)) + .verifyComplete(); + } + + //scalarCallable empty/error/just are not instantiating MonoSingleOptionalCallable and are covered in MonoSingleTest + //we still cover the case where a callable source throws + + @Test + void failingCallable() { + StepVerifier.create(new MonoSingleOptionalCallable<>(() -> { throw new IllegalStateException("test"); } )) + .verifyErrorMessage("test"); + } + + @Test + void emptyCallable() { + StepVerifier.create(new MonoSingleOptionalCallable<>(() -> null)) + .expectNext(Optional.empty()) + .verifyComplete(); + } + + @Test + void valuedCallable() { + @SuppressWarnings("unchecked") + Callable fluxCallable = (Callable) Mono.fromCallable(() -> 1).flux(); + + + StepVerifier.create(new MonoSingleOptionalCallable<>(fluxCallable)) + .expectNext(Optional.of(1)) + .verifyComplete(); + } + + @Test + void fusionMonoSingleOptionalCallableDoesntTriggerFusion() { + Mono> fusedCase = Mono + .fromCallable(() -> 1) + .singleOptional(); + + assertThat(fusedCase) + .as("fusedCase assembly check") + .isInstanceOf(MonoSingleOptionalCallable.class) + .isNotInstanceOf(Fuseable.class); + + assertThatCode(() -> fusedCase.filter(v -> true).block()) + .as("fusedCase fused") + .doesNotThrowAnyException(); + } + + @Test + void scanOperator(){ + MonoSingleOptionalCallable test = new MonoSingleOptionalCallable<>(() -> "foo"); + + assertThat(test.scan(Scannable.Attr.RUN_STYLE)).isSameAs(Scannable.Attr.RunStyle.SYNC); + } + +} diff --git a/reactor-core/src/test/java/reactor/core/publisher/MonoSingleOptionalTest.java b/reactor-core/src/test/java/reactor/core/publisher/MonoSingleOptionalTest.java index 0451d1a0e0..0f0e7bb772 100644 --- a/reactor-core/src/test/java/reactor/core/publisher/MonoSingleOptionalTest.java +++ b/reactor-core/src/test/java/reactor/core/publisher/MonoSingleOptionalTest.java @@ -1,178 +1,186 @@ -/* - * Copyright (c) 2017-2021 VMware Inc. or its affiliates, All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package reactor.core.publisher; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; - -import java.util.Optional; -import java.util.concurrent.Callable; -import java.util.function.Function; - -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.reactivestreams.Subscription; - -import reactor.core.CoreSubscriber; -import reactor.core.Fuseable; -import reactor.core.Scannable; -import reactor.test.StepVerifier; - -public class MonoSingleOptionalTest { - - @Nested - class ConcreteClassConsistency { - // tests Mono.singleOptional returned classes - - @Test - void monoWithScalarEmpty() { - Mono source = Mono.empty(); - Mono> singleOptional = source.singleOptional(); - - assertThat(source).as("source").isInstanceOf(Fuseable.ScalarCallable.class); - assertThat(singleOptional).as("singleOptional") - .isInstanceOf(MonoJust.class) - .isInstanceOf(Fuseable.ScalarCallable.class); - } - - @Test - void monoWithScalarError() { - Mono source = Mono.error(new IllegalStateException("test")); - Mono> singleOptional = source.singleOptional(); - - assertThat(source).as("source").isInstanceOf(Fuseable.ScalarCallable.class); - assertThat(singleOptional).as("singleOptional") - .isInstanceOf(MonoError.class) - .isInstanceOf(Fuseable.ScalarCallable.class); - } - - @Test - void monoWithScalarValue() { - Mono source = Mono.just(1); - Mono> single = source.singleOptional(); - - assertThat(source).as("source").isInstanceOf(Fuseable.ScalarCallable.class); - assertThat(single).as("singleOptional") - .isInstanceOf(MonoJust.class) - .isInstanceOf(Fuseable.ScalarCallable.class); - } - - @Test - void monoWithCallable() { - Mono source = Mono.fromSupplier(() -> 1); - Mono> single = source.singleOptional(); - - assertThat(source).as("source") - .isInstanceOf(Callable.class) - .isNotInstanceOf(Fuseable.ScalarCallable.class); - assertThat(single).as("singleOptional").isInstanceOf(MonoSingleOptionalCallable.class); - } - - @Test - void monoWithNormal() { - Mono source = Mono.just(1).hide(); - Mono> single = source.singleOptional(); - - assertThat(source).as("source").isNotInstanceOf(Callable.class); //excludes ScalarCallable too - assertThat(single).as("singleOptional").isInstanceOf(MonoSingleOptional.class); - } - } - - @Test - void source1Null() { - assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> { - new MonoSingleOptional<>(null); - }); - } - - @Test - public void callableEmpty() { - StepVerifier.create(Mono.empty().singleOptional()) - .expectNext(Optional.empty()) - .verifyComplete(); - } - - @Test - public void callableValued() { - StepVerifier.create(Mono.just("foo").singleOptional()) - .expectNext(Optional.of("foo")) - .verifyComplete(); - } - - @Test - public void normalEmpty() { - StepVerifier.create(Mono.empty().hide().singleOptional()) - .expectNext(Optional.empty()) - .verifyComplete(); - } - - @Test - public void normalValued() { - StepVerifier.create(Mono.just("foo").hide().singleOptional()) - .expectNext(Optional.of("foo")) - .verifyComplete(); - } - - @Test - void fusionMonoSingleFusion() { - Mono> fusedCase = Mono - .just(1) - .map(Function.identity()) - .singleOptional(); - - assertThat(fusedCase) - .as("fusedCase assembly check") - .isInstanceOf(MonoSingleOptional.class) - .isNotInstanceOf(Fuseable.class); - - assertThatCode(() -> fusedCase.filter(v -> true).block()) - .as("fusedCase fused") - .doesNotThrowAnyException(); - } - - @Test - public void scanOperator(){ - MonoSingleOptional test = new MonoSingleOptional<>(Mono.just("foo")); - - assertThat(test.scan(Scannable.Attr.RUN_STYLE)).isSameAs(Scannable.Attr.RunStyle.SYNC); - } - - @Test - public void scanSubscriber() { - CoreSubscriber> - actual = new LambdaMonoSubscriber<>(null, e -> {}, null, null); - MonoSingleOptional.SingleOptionalSubscriber test = new MonoSingleOptional.SingleOptionalSubscriber<>( - actual); - Subscription parent = Operators.emptySubscription(); - test.onSubscribe(parent); - - assertThat(test.scan(Scannable.Attr.PREFETCH)).isEqualTo(Integer.MAX_VALUE); - - assertThat(test.scan(Scannable.Attr.PARENT)).isSameAs(parent); - assertThat(test.scan(Scannable.Attr.ACTUAL)).isSameAs(actual); - assertThat(test.scan(Scannable.Attr.RUN_STYLE)).isSameAs(Scannable.Attr.RunStyle.SYNC); - - assertThat(test.scan(Scannable.Attr.TERMINATED)).isFalse(); - test.onError(new IllegalStateException("boom")); - assertThat(test.scan(Scannable.Attr.TERMINATED)).isTrue(); - - assertThat(test.scan(Scannable.Attr.CANCELLED)).isFalse(); - test.cancel(); - assertThat(test.scan(Scannable.Attr.CANCELLED)).isTrue(); - } -} +/* + * Copyright (c) 2017-2023 VMware Inc. or its affiliates, All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package reactor.core.publisher; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +import java.util.Optional; +import java.util.concurrent.Callable; +import java.util.function.Function; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.reactivestreams.Subscription; + +import reactor.core.CoreSubscriber; +import reactor.core.Fuseable; +import reactor.core.Scannable; +import reactor.test.StepVerifier; + +public class MonoSingleOptionalTest { + + @Nested + class ConcreteClassConsistency { + // tests Mono.singleOptional returned classes + + @Test + void monoWithScalarEmpty() { + Mono source = Mono.empty(); + Mono> singleOptional = source.singleOptional(); + + assertThat(source).as("source").isInstanceOf(Fuseable.ScalarCallable.class); + assertThat(singleOptional).as("singleOptional") + .isInstanceOf(MonoJust.class) + .isInstanceOf(Fuseable.ScalarCallable.class); + } + + @Test + void monoWithScalarError() { + Mono source = Mono.error(new IllegalStateException("test")); + Mono> singleOptional = source.singleOptional(); + + assertThat(source).as("source").isInstanceOf(Fuseable.ScalarCallable.class); + assertThat(singleOptional).as("singleOptional") + .isInstanceOf(MonoError.class) + .isInstanceOf(Fuseable.ScalarCallable.class); + } + + @Test + void monoWithScalarValue() { + Mono source = Mono.just(1); + Mono> single = source.singleOptional(); + + assertThat(source).as("source").isInstanceOf(Fuseable.ScalarCallable.class); + assertThat(single).as("singleOptional") + .isInstanceOf(MonoJust.class) + .isInstanceOf(Fuseable.ScalarCallable.class); + } + + @Test + void monoWithCallable() { + Mono source = Mono.fromSupplier(() -> 1); + Mono> single = source.singleOptional(); + + assertThat(source).as("source") + .isInstanceOf(Callable.class) + .isNotInstanceOf(Fuseable.ScalarCallable.class); + assertThat(single).as("singleOptional").isInstanceOf(MonoSingleOptionalCallable.class); + } + + @Test + void monoWithNormal() { + Mono source = Mono.just(1).hide(); + Mono> single = source.singleOptional(); + + assertThat(source).as("source").isNotInstanceOf(Callable.class); // excludes + // ScalarCallable + // too + assertThat(single).as("singleOptional").isInstanceOf(MonoSingleOptional.class); + } + } + + @Test + void source1Null() { + assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> { + new MonoSingleOptional<>(null); + }); + } + + @Test + public void callableEmpty() { + StepVerifier.create(Mono.empty().singleOptional()) + .expectNext(Optional.empty()) + .verifyComplete(); + } + + @Test + public void callableValued() { + StepVerifier.create(Mono.just("foo").singleOptional()) + .expectNext(Optional.of("foo")) + .verifyComplete(); + } + + @Test + public void callableError() { + StepVerifier.create(Mono.error(new IllegalStateException("failed")).singleOptional()) + .expectErrorMessage("failed"); + } + + @Test + public void normalEmpty() { + StepVerifier.create(Mono.empty().hide().singleOptional()) + .expectNext(Optional.empty()) + .verifyComplete(); + } + + @Test + public void normalValued() { + StepVerifier.create(Mono.just("foo").hide().singleOptional()) + .expectNext(Optional.of("foo")) + .verifyComplete(); + } + + @Test + public void normalError() { + StepVerifier.create(Mono.error(new IllegalStateException("failed")).hide().singleOptional()) + .expectErrorMessage("failed"); + } + + @Test + void fusionMonoSingleFusion() { + Mono> fusedCase = Mono.just(1).map(Function.identity()).singleOptional(); + + assertThat(fusedCase).as("fusedCase assembly check") + .isInstanceOf(MonoSingleOptional.class) + .isNotInstanceOf(Fuseable.class); + + assertThatCode(() -> fusedCase.filter(v -> true).block()).as("fusedCase fused") + .doesNotThrowAnyException(); + } + + @Test + public void scanOperator() { + MonoSingleOptional test = new MonoSingleOptional<>(Mono.just("foo")); + + assertThat(test.scan(Scannable.Attr.RUN_STYLE)).isSameAs(Scannable.Attr.RunStyle.SYNC); + } + + @Test + public void scanSubscriber() { + CoreSubscriber> actual = new LambdaMonoSubscriber<>(null, e -> {}, null, null); + MonoSingleOptional.SingleOptionalSubscriber test = new MonoSingleOptional.SingleOptionalSubscriber<>( + actual); + Subscription parent = Operators.emptySubscription(); + test.onSubscribe(parent); + + assertThat(test.scan(Scannable.Attr.PREFETCH)).isEqualTo(Integer.MAX_VALUE); + + assertThat(test.scan(Scannable.Attr.PARENT)).isSameAs(parent); + assertThat(test.scan(Scannable.Attr.ACTUAL)).isSameAs(actual); + assertThat(test.scan(Scannable.Attr.RUN_STYLE)).isSameAs(Scannable.Attr.RunStyle.SYNC); + + assertThat(test.scan(Scannable.Attr.TERMINATED)).isFalse(); + test.onError(new IllegalStateException("boom")); + assertThat(test.scan(Scannable.Attr.TERMINATED)).isTrue(); + + assertThat(test.scan(Scannable.Attr.CANCELLED)).isFalse(); + test.cancel(); + assertThat(test.scan(Scannable.Attr.CANCELLED)).isTrue(); + } +}