
reactor.core.publisher.Mono Maven / Gradle / Ivy
/*
* Copyright (c) 2011-2017 Pivotal Software Inc, 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
*
* http://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.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
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 java.util.stream.LongStream;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import reactor.core.CoreSubscriber;
import reactor.core.Disposable;
import reactor.core.Fuseable;
import reactor.core.Scannable;
import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Scheduler.Worker;
import reactor.core.scheduler.Schedulers;
import reactor.util.Logger;
import reactor.util.annotation.Nullable;
import reactor.util.concurrent.Queues;
import reactor.util.context.Context;
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.Tuples;
/**
* A Reactive Streams {@link Publisher} with basic rx operators that completes successfully by emitting an element, or
* with an error.
*
*
*
*
*
*
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 Publisher {
// ==============================================================================================================
// 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 RuntimeExeption("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 new {@link Mono} factory
*/
public static Mono defer(Supplier extends Mono extends T>> supplier) {
return onAssembly(new MonoDefer<>(supplier));
}
/**
* 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.toMillis(), TimeUnit.MILLISECONDS, 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 failed {@link Mono}
*/
public static Mono error(Throwable error) {
return onAssembly(new MonoError<>(error));
}
/**
* 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 first(Mono extends T>... monos) {
return onAssembly(new MonoFirst<>(monos));
}
/**
* Pick the first available result coming from any of the given monos and populate a new {@literal Mono}.
*
*
*
*
* @param monos The monos to use.
* @param The type of the function result.
*
* @return a {@link Mono}.
*/
public static Mono first(Iterable extends Mono extends T>> monos) {
return onAssembly(new MonoFirst<>(monos));
}
/**
* 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`.
*
*
*
* @param source the {@link Publisher} source
* @param the source type
*
* @return the next item emitted as a {@link Mono}
*/
public static Mono from(Publisher extends T> source) {
if (source instanceof Mono) {
@SuppressWarnings("unchecked")
Mono casted = (Mono) source;
return casted;
}
if (source instanceof Flux) {
@SuppressWarnings("unchecked")
Flux casted = (Flux) source;
return casted.next();
}
return onAssembly(new MonoFromPublisher<>(source));
}
/**
* 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 extends T> supplier) {
return onAssembly(new MonoCallable<>(supplier));
}
/**
* Create a {@link Mono}, producing its value using the provided {@link CompletionStage}.
*
*
*
*
* @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 extends T> completionStage) {
return onAssembly(new MonoCompletionStage<>(completionStage));
}
/**
* Convert a {@link Publisher} to a {@link Mono} without any cardinality check
* (ie this method doesn't check if the source is already a Mono, nor cancels the
* source past the first element). Conversion 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.
*
* @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 extends I> source){
if(source instanceof Mono){
@SuppressWarnings("unchecked")
Mono m = (Mono)source;
return m;
}
if(source instanceof Flux){
@SuppressWarnings("unchecked")
Flux f = (Flux)source;
if(source instanceof Fuseable){
return onAssembly(new MonoSourceFluxFuseable<>(f));
}
return onAssembly(new MonoSourceFlux<>(f));
}
if(source instanceof Fuseable){
return onAssembly(new MonoSourceFuseable<>(source));
}
return onAssembly(new MonoSource<>(source));
}
/**
* Create a {@link Mono}, producing its value using the provided {@link CompletableFuture}.
*
*
*
*
* @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 extends T> future) {
return onAssembly(new MonoCompletionStage<>(future));
}
/**
* 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 extends T> 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.
*
*
*
*
* @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 extends T> 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 extends T> source1, Publisher extends T> 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 extends T> source1, Publisher extends T> source2,
BiPredicate super T, ? super T> 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 extends T> source1,
Publisher extends T> source2,
BiPredicate super T, ? super T> isEqual, int prefetch) {
return onAssembly(new MonoSequenceEqual<>(source1, source2, isEqual, prefetch));
}
/**
* Create a {@link Mono} emitting the {@link Context} available on subscribe.
* If no Context is available, the mono will simply emit the
* {@link Context#empty() empty Context}.
*
*
*
*
*
* @return a new {@link Mono} emitting current context
* @see #subscribe(CoreSubscriber)
*/
public static Mono subscriberContext() {
return onAssembly(MonoCurrentContext.INSTANCE);
}
/**
* 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.
*
*
- Eager resource cleanup happens just before the source termination and exceptions raised by the cleanup
* Consumer may override the terminal event.
- 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 push to true to clean before terminating downstream subscribers
* @param emitted type
* @param resource type
*
* @return new {@link Mono}
*/
public static Mono using(Callable extends D> resourceSupplier,
Function super D, ? extends Mono extends T>> sourceSupplier,
Consumer super D> 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.
*
* Eager resource cleanup happens just before the source termination and exceptions raised by the cleanup Consumer
* may override the terminal event.
*
*
*
* @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 extends D> resourceSupplier,
Function super D, ? extends Mono extends T>> sourceSupplier,
Consumer super D> resourceCleanup) {
return using(resourceSupplier, sourceSupplier, resourceCleanup, true);
}
/**
* Aggregate given publishers into a new {@literal Mono} that will be fulfilled
* when all of the given {@literal sources} have been fulfilled. 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 been fulfilled.
* 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 extends Publisher>> 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 been fulfilled. If any Publisher
* terminates without value, the returned sequence will be terminated immediately and
* pending results cancelled. 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 extends Publisher>> 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 been fulfilled. 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 been fulfilled, aggregating their values into a {@link Tuple2}.
* An error will cause pending results to be cancelled and immediate error emission to the
* returned {@link Mono}.
*
*
*
*
* @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 source1
* @param type of the value from source2
*
* @return a {@link Mono}.
*/
public static Mono> zip(Mono extends T1> p1, Mono extends T2> 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 been fulfilled, aggregating their values as defined by the combinator function.
* An error will cause pending results to be cancelled and immediate error emission to the
* returned {@link Mono}.
*
*
*
*
* @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 source1
* @param type of the value from source2
* @param output value
*
* @return a {@link Mono}.
*/
public static Mono zip(Mono extends T1> p1, Mono
extends T2> p2, BiFunction super T1, ? super T2, ? extends O> 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 been fulfilled, aggregating their values into a {@link Tuple3}.
* An error will cause pending results to be cancelled and immediate error emission to the
* returned {@link Mono}.
*
*
*
*
* @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 source1
* @param type of the value from source2
* @param type of the value from source3
*
* @return a {@link Mono}.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static Mono> zip(Mono extends T1> p1, Mono extends T2> p2, Mono extends T3> 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 been fulfilled, aggregating their values into a {@link Tuple4}.
* An error will cause pending results to be cancelled and immediate error emission to the
* returned {@link Mono}.
*
*
*
*
* @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 source1
* @param type of the value from source2
* @param type of the value from source3
* @param type of the value from source4
*
* @return a {@link Mono}.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static Mono> zip(Mono extends T1> p1,
Mono extends T2> p2,
Mono extends T3> p3,
Mono extends T4> 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 been fulfilled, aggregating their values into a {@link Tuple5}.
* An error will cause pending results to be cancelled and immediate error emission to the
* returned {@link Mono}.
*
*
*
*
* @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 source1
* @param type of the value from source2
* @param type of the value from source3
* @param type of the value from source4
* @param type of the value from source5
*
* @return a {@link Mono}.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static Mono> zip(Mono extends T1> p1,
Mono extends T2> p2,
Mono extends T3> p3,
Mono extends T4> p4,
Mono extends T5> 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 been fulfilled, aggregating their values into a {@link Tuple6}.
* An error will cause pending results to be cancelled and immediate error emission to the
* returned {@link Mono}.
*
*
*
*
* @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 source1
* @param type of the value from source2
* @param type of the value from source3
* @param type of the value from source4
* @param type of the value from source5
* @param type of the value from source6
*
* @return a {@link Mono}.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static Mono> zip(Mono extends T1> p1,
Mono extends T2> p2,
Mono extends T3> p3,
Mono extends T4> p4,
Mono extends T5> p5,
Mono extends T6> p6) {
return onAssembly(new MonoZip(false, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5, p6));
}
/**
* Aggregate given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal
* Monos} have been fulfilled, aggregating their values according to the provided combinator function.
* If any Mono terminates without value, the returned sequence will be terminated immediately and pending results cancelled.
*
*
*
*
*
* @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 extends Mono>> monos, Function super Object[], ? extends R> 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 been fulfilled, aggregating their values according to the provided combinator function.
* An error will cause pending results to be cancelled and immediate error emission to the
* returned {@link Mono}.
*
*
*
* @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 super Object[], ? extends R> 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 been fulfilled, aggregating their values into a {@link Tuple2} and delaying errors.
* 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 source1
* @param type of the value from source2
*
* @return a {@link Mono}.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static Mono> zipDelayError(Mono extends T1> p1, Mono extends T2> 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 been fulfilled, aggregating their values into a {@link Tuple3} and delaying errors.
* If several 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 p3 The third upstream {@link Publisher} to subscribe to.
* @param type of the value from source1
* @param type of the value from source2
* @param type of the value from source3
*
* @return a {@link Mono}.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static Mono> zipDelayError(Mono extends T1> p1, Mono extends T2> p2, Mono extends T3> 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 been fulfilled, aggregating their values into a {@link Tuple4} and delaying errors.
* If several Monos error, the 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 source1
* @param type of the value from source2
* @param type of the value from source3
* @param type of the value from source4
*
* @return a {@link Mono}.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static Mono> zipDelayError(Mono extends T1> p1,
Mono extends T2> p2,
Mono extends T3> p3,
Mono extends T4> 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 been fulfilled, aggregating their values into a {@link Tuple5} and delaying errors.
* If several Monos error, the 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 source1
* @param type of the value from source2
* @param type of the value from source3
* @param type of the value from source4
* @param type of the value from source5
*
* @return a {@link Mono}.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static Mono> zipDelayError(Mono extends T1> p1,
Mono extends T2> p2,
Mono extends T3> p3,
Mono extends T4> p4,
Mono extends T5> 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 been fulfilled, aggregating their values into a {@link Tuple6} and delaying errors.
* If several Monos error, the 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 source1
* @param type of the value from source2
* @param type of the value from source3
* @param type of the value from source4
* @param type of the value from source5
* @param type of the value from source6
*
* @return a {@link Mono}.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static Mono> zipDelayError(Mono extends T1> p1,
Mono extends T2> p2,
Mono extends T3> p3,
Mono extends T4> p4,
Mono extends T5> p5,
Mono extends T6> p6) {
return onAssembly(new MonoZip(true, a -> Tuples.fromArray((Object[])a), p1, p2, p3, p4, p5, p6));
}
/**
* Aggregate given monos into a new {@literal Mono} that will be fulfilled when all of the given {@literal
* Monos} have been fulfilled. If any Mono terminates without value, the returned sequence will be terminated
* immediately and pending results cancelled. Errors from the sources are delayed.
* If several Monos error, the 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 extends Mono>> monos, Function super Object[], ? extends R> 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 been fulfilled, aggregating their values according to
* the provided combinator function and delaying errors.
* If several Monos error, the 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 super Object[], ? extends R>
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 #compose for a bounded conversion to {@link Publisher}
*/
public final
P as(Function super Mono, 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<>();
onLastAssembly(this).subscribe(Operators.toCoreSubscriber(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<>();
onLastAssembly(this).subscribe(Operators.toCoreSubscriber(subscriber));
return subscriber.blockingGet(timeout.toMillis(), TimeUnit.MILLISECONDS);
}
/**
* 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.
*
*
*
* @return a replaying {@link Mono}
*/
public final Mono cache() {
return onAssembly(new MonoProcessor<>(this));
}
public final Mono cache(Duration ttl) {
return onAssembly(new MonoCacheTime<>(this, ttl, Schedulers.parallel()));
}
/**
* 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 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.
*
* @return the assembly tracing {@link Mono}
*/
public final Mono checkpoint() {
return checkpoint(null, true);
}
/**
* Activate 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.
*
* @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 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.
*
* @param description a description (must be unique enough if forceStackTrace is push
* 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) {
return new MonoOnAssembly<>(this, description, !forceStackTrace);
}
/**
* 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:
*
*
* {@code flux.compose(Mono::from).subscribe() }
*
*
* @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 #as as() for a loose conversion to an arbitrary type
* @see #transform(Function)
*/
public final Mono compose(Function super Mono, ? extends Publisher> transformer) {
return defer(() -> from(transformer.apply(this)));
}
/**
* 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 extends T> other) {
return Flux.concat(this, other);
}
/**
* 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.toMillis(), TimeUnit.MILLISECONDS, 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 super T, ? extends Publisher>> 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.
*
*
*