Skip to content

Commit

Permalink
Enhance ActionListener documentation (#104239)
Browse files Browse the repository at this point in the history
Improve comments for ActionListener#delegateFailure and
SubscribableListener.

Closes #103829
  • Loading branch information
DiannaHohensee authored Jan 18, 2024
1 parent ae87d32 commit cf05e28
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -89,19 +89,21 @@ default ActionListener<Response> delegateResponse(BiConsumer<ActionListener<Resp
}

/**
* Creates a listener that delegates all exceptions it receives to another listener.
* Creates a new listener, wrapping this one, that overrides {@link #onResponse} handling with the given {@code bc} consumer.
* {@link #onFailure(Exception)} handling is delegated to the original listener. Exceptions in {@link #onResponse} are forbidden.
*
* @param bc BiConsumer invoked with delegate listener and response
* @param bc {@link BiConsumer} invoked via {@link #onResponse} with the original listener and the response with which the new listener
* was completed.
* @param <T> Type of the delegating listener's response
* @return Delegating listener
* @return a new listener that delegates failures to this listener and runs {@code bc} on a response.
*/
default <T> ActionListener<T> delegateFailure(BiConsumer<ActionListener<Response>, T> bc) {
return new ActionListenerImplementations.DelegatingFailureActionListener<>(this, bc);
}

/**
* Same as {@link #delegateFailure(BiConsumer)} except that any failure thrown by {@code bc} or the delegate listener's
* {@link #onResponse} will be passed to the delegate listeners {@link #onFailure(Exception)}.
* Same as {@link #delegateFailure(BiConsumer)} except that any failure thrown by {@code bc} or the original listener's
* {@link #onResponse} will be passed to the original listener's {@link #onFailure(Exception)}.
*/
default <T> ActionListener<T> delegateFailureAndWrap(CheckedBiConsumer<ActionListener<Response>, T, ? extends Exception> bc) {
return new ActionListenerImplementations.ResponseWrappingActionListener<>(this, bc);
Expand Down Expand Up @@ -150,7 +152,7 @@ public String toString() {
* the sense that an exception from the {@code onResponse} consumer is passed into the {@code onFailure} consumer.
* <p>
* If the {@code onFailure} argument is {@code listener::onFailure} for some other {@link ActionListener}, prefer to use
* {@link #delegateFailureAndWrap} instead.
* {@link #delegateFailureAndWrap} instead for performance reasons.
* @param onResponse the checked consumer of the response, executed when the listener is completed successfully. If it throws an
* exception, the exception is passed to the {@code onFailure} consumer.
* @param onFailure the consumer of the failure, executed when the listener is completed with an exception (or it is completed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,11 @@ public String toString() {
}
}

/**
* Replaces the onResponse handling of a given ActionListener with a lambda that receives both the original listener and a response.
* This is useful when a listener is needed to do some additional work with a response before passing a response on to the original
* listener.
*/
static final class DelegatingFailureActionListener<T, R> extends DelegatingActionListener<T, R> {

private final BiConsumer<ActionListener<R>, T> bc;
Expand All @@ -221,6 +226,10 @@ public String toString() {
}
}

/**
* The same as {@link DelegatingFailureActionListener} with the addition of exception handling in {@link #onResponse(Object)} to forward
* any exceptions to {@link #onFailure(Exception)}.
*/
static final class ResponseWrappingActionListener<T, R> extends DelegatingActionListener<T, R> {

private final CheckedBiConsumer<ActionListener<R>, T, ? extends Exception> bc;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@
import static org.elasticsearch.action.ActionListenerImplementations.safeOnFailure;

/**
* A wrapper around an {@link ActionListener} which delegates failures safely to the inner listener's {@link ActionListener#onFailure}
* method and which has a {@link #toString()} implementation which describes this class and the delegate.
* A wrapper around an {@link ActionListener} {@code L} that by default delegates failures to {@code L}'s {@link ActionListener#onFailure}
* method. The wrapper also provides a {@link #toString()} implementation that describes this class and the delegate.
* <p>
* This is a useful base class for creating ActionListener wrappers that override the {@link #onResponse} handling, with access to
* {@code L}, while retaining all of {@code L}'s other handling. It can also be useful to override other methods to do new work with access
* to {@code L}.
*/
public abstract class DelegatingActionListener<Response, DelegateResponse> implements ActionListener<Response> {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,12 @@
* An {@link ActionListener} to which other {@link ActionListener} instances can subscribe, such that when this listener is completed it
* fans-out its result to the subscribed listeners.
* <p>
* Similar to {@link ListenableActionFuture} and {@link ListenableFuture} except for its handling of exceptions: if this listener is
* completed exceptionally then the exception is passed to subscribed listeners without modification.
* Exceptions are passed to subscribed listeners without modification. {@link ListenableActionFuture} and {@link ListenableFuture} are child
* classes that provide additional exception handling.
* <p>
* Often this will be used to chain together a sequence of async actions, similarly to {@link CompletionStage} (without the
* {@code catch (Throwable t)}), such as in the following example:
* A sequence of async steps can be chained together using a series of {@link SubscribableListener}s, similar to {@link CompletionStage}
* (without the {@code catch (Throwable t)}). Listeners can be created for each step, where the next step subscribes to the result of the
* previous, using utilities like {@link #andThen(CheckedBiConsumer)}. The following example demonstrates how this might be used:
* <pre>{@code
* private void exampleAsyncMethod(String request, List<Long> items, ActionListener<Boolean> finalListener) {
* SubscribableListener
Expand Down

0 comments on commit cf05e28

Please sign in to comment.