Skip to content

Commit

Permalink
Improve javadoc for the 'function' core package.
Browse files Browse the repository at this point in the history
Signed-off-by: Sjoerd Talsma <sjoerdtalsma@users.noreply.github.com>
  • Loading branch information
sjoerdtalsma committed Nov 19, 2024
1 parent b394cc9 commit c1f56d7
Show file tree
Hide file tree
Showing 14 changed files with 998 additions and 97 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/
/**
* ThreadLocal context management in concurrent applications.
* Context management for ThreadLocal values in concurrent applications.
*
* <h2>{@linkplain nl.talsmasoftware.context.core.concurrent.ContextAwareExecutorService ContextAwareExecutorService}</h2>
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,32 +27,95 @@
import static java.util.Objects.requireNonNull;

/**
* A wrapper for {@link BiConsumer} that {@link ContextSnapshot#reactivate() reactivates a context snapshot} before
* calling a delegate.
* {@linkplain BiConsumer} that {@linkplain ContextSnapshot#reactivate() reactivates a context snapshot}
* while passing the values.
*
* <p>
* Implemented as a {@linkplain nl.talsmasoftware.context.core.delegation.Wrapper wrapper} for {@link BiConsumer}.
*
* <p>
* The reactivated context snapshot will be safely closed after the delegate function has been applied.
*
* @param <T> the type of the first argument to the operation.
* @param <U> the type of the second argument to the operation.
* @author Sjoerd Talsma
*/
public class BiConsumerWithContext<T, U> extends WrapperWithContextAndConsumer<BiConsumer<T, U>> implements BiConsumer<T, U> {
private static final Logger LOGGER = Logger.getLogger(BiConsumerWithContext.class.getName());

/**
* Creates a new bi-consumer that performs the following steps, in-order:
* <ol>
* <li>{@linkplain ContextSnapshot#reactivate() reactivate} the given snapshot
* <li>accept the values by passing them to the delegate bi-consumer
* <li>close the {@linkplain ContextSnapshot.Reactivation reactivation}
* </ol>
*
* @param snapshot Context snapshot to run the delegate task in.
* @param delegate The delegate bi-consumer to pass the values to.
*/
public BiConsumerWithContext(ContextSnapshot snapshot, BiConsumer<T, U> delegate) {
this(snapshot, delegate, null);
}

public BiConsumerWithContext(ContextSnapshot snapshot, BiConsumer<T, U> delegate, Consumer<ContextSnapshot> consumer) {
super(snapshot, delegate, consumer);
/**
* Creates a new bi-consumer that performs the following steps, in-order:
* <ol>
* <li>{@linkplain ContextSnapshot#reactivate() reactivate} the given snapshot
* <li>accept the values by passing them to the delegate bi-consumer
* <li><em>if snapshot consumer is non-null,</em>
* pass it a {@linkplain ContextManagers#createContextSnapshot() new context snapshot}
* <li>close the {@linkplain ContextSnapshot.Reactivation reactivation}
* </ol>
*
* @param snapshot Context snapshot to run the delegate task in.
* @param delegate The delegate bi-consumer to pass the values to.
* @param snapshotConsumer Consumer accepting the resulting context snapshot after the delegate task ran
* (optional, may be {@code null}).
*/
public BiConsumerWithContext(ContextSnapshot snapshot, BiConsumer<T, U> delegate, Consumer<ContextSnapshot> snapshotConsumer) {
super(snapshot, delegate, snapshotConsumer);
}

protected BiConsumerWithContext(Supplier<ContextSnapshot> supplier, BiConsumer<T, U> delegate, Consumer<ContextSnapshot> consumer) {
super(supplier, delegate, consumer);
/**
* Protected constructor for use with a snapshot 'holder' object that acts as both snapshot supplier and -consumer.
*
* <p>
* This constructor is not for general use. Care must be taken to capture the context snapshot <em>before</em> the
* bi-consumer is called, otherwise the snapshot being reactivated would effectively update the context
* to the same values just captured.
*
* @param snapshotSupplier Supplier for the context snapshot that was previously captured.
* @param delegate The delegate bi-consumer to pass the values to.
* @param snapshotConsumer Consumer accepting the resulting context snapshot after the delegate task ran
* (optional, may be {@code null}).
*/
protected BiConsumerWithContext(Supplier<ContextSnapshot> snapshotSupplier, BiConsumer<T, U> delegate, Consumer<ContextSnapshot> snapshotConsumer) {
super(snapshotSupplier, delegate, snapshotConsumer);
}

/**
* Accept the values by passing them to the delegate bi-consumer within a reactivated context snapshot.
*
* <p>
* The implementation performs the following steps, in-order:
* <ol>
* <li>{@linkplain ContextSnapshot#reactivate() reactivate} the given snapshot
* <li>accept the values by passing them to the delegate bi-consumer
* <li><em>if snapshot consumer is non-null,</em>
* pass it a {@linkplain ContextManagers#createContextSnapshot() new context snapshot}
* <li>close the {@linkplain ContextSnapshot.Reactivation reactivation}
* </ol>
*
* @param in1 the first input argument to be passed to the delegate bi-consumer.
* @param in2 the second input argument to be passed to the delegate bi-consumer.
*/
@Override
public void accept(T t, U u) {
public void accept(T in1, U in2) {
try (ContextSnapshot.Reactivation context = snapshot().reactivate()) {
try { // inner 'try' is needed: https://github.com/talsma-ict/context-propagation/pull/56#discussion_r201590623
LOGGER.log(Level.FINEST, "Delegating accept method with {0} to {1}.", new Object[]{context, delegate()});
delegate().accept(t, u);
delegate().accept(in1, in2);
} finally {
if (contextSnapshotConsumer != null) {
ContextSnapshot resultSnapshot = ContextManagers.createContextSnapshot();
Expand All @@ -63,6 +126,28 @@ public void accept(T t, U u) {
}
}

/**
* Constructs a new bi-consumer that accepts values by passing them to the delegate bi-consumer within a
* reactivated context snapshot, however <em>before closing the reactivation</em> the {@code after} operation is
* also called within the reactivated context.
*
* <p>
* The resulting bi-consumer performs the following steps, in-order:
* <ol>
* <li>{@linkplain ContextSnapshot#reactivate() reactivate} the given snapshot
* <li>accept the values by:
* <ol>
* <li>passing them to the delegate bi-consumer
* <li>passing them to the {@code after} bi-consumer
* </ol>
* <li><em>if snapshot consumer is non-null,</em>
* pass it a {@linkplain ContextManagers#createContextSnapshot() new context snapshot}
* <li>close the {@linkplain ContextSnapshot.Reactivation reactivation}
* </ol>
*
* @param after the operation to perform after this operation
* @return new bi-consumer that also applies the {@code after} operation within the reactivated context snapshot.
*/
@Override
public BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> after) {
requireNonNull(after, "Cannot post-process with after bi-consumer <null>.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,101 @@
import static java.util.Objects.requireNonNull;

/**
* A wrapper for {@link BiFunction} that {@link ContextSnapshot#reactivate() reactivates a context snapshot} before
* calling a delegate.
* {@linkplain BiFunction} that {@linkplain ContextSnapshot#reactivate() reactivates a context snapshot}
* when {@linkplain #apply(Object, Object) applying} the function.
*
* <p>
* Implemented as a {@linkplain nl.talsmasoftware.context.core.delegation.Wrapper wrapper} for {@link BiFunction}.
*
* <p>
* The reactivated context snapshot will be safely closed after the delegate function has been applied.
*
* @param <IN1> the type of the first argument to the function.
* @param <IN2> the type of the second argument to the function.
* @param <OUT> the type of the result of the function.
* @author Sjoerd Talsma
*/
public class BiFunctionWithContext<IN1, IN2, OUT> extends WrapperWithContextAndConsumer<BiFunction<IN1, IN2, OUT>> implements BiFunction<IN1, IN2, OUT> {
private static final Logger LOGGER = Logger.getLogger(BiFunctionWithContext.class.getName());

/**
* Creates a new bi-function with context.
*
* <p>
* This function performs the following steps, in-order:
* <ol>
* <li>{@linkplain ContextSnapshot#reactivate() reactivate} the given snapshot
* <li>apply the delegate function
* <li>close the {@linkplain ContextSnapshot.Reactivation reactivation}
* <li>return the result from the delegate function call (or throw runtime exception if the delegate did).
* </ol>
*
* @param snapshot Context snapshot to apply the delegate function in.
* @param delegate The delegate bi-function to apply.
*/
public BiFunctionWithContext(ContextSnapshot snapshot, BiFunction<IN1, IN2, OUT> delegate) {
this(snapshot, delegate, null);
}

public BiFunctionWithContext(ContextSnapshot snapshot, BiFunction<IN1, IN2, OUT> delegate, Consumer<ContextSnapshot> consumer) {
super(snapshot, delegate, consumer);
/**
* Creates a new bi-function with context.
*
* <p>
* This function performs the following steps, in-order:
* <ol>
* <li>{@linkplain ContextSnapshot#reactivate() reactivate} the given snapshot
* <li>apply the delegate function
* <li><em>if snapshot consumer is non-null,</em>
* pass a {@linkplain ContextManagers#createContextSnapshot() new context snapshot} to the consumer
* <li>close the {@linkplain ContextSnapshot.Reactivation reactivation}
* <li>return the result from the delegate function call (or throw runtime exception if the delegate did).
* </ol>
*
* @param snapshot Context snapshot to apply the delegate function in.
* @param delegate The delegate bi-function to apply.
* @param snapshotConsumer Consumer accepting the resulting context snapshot after the delegate function was applied
* (optional, may be {@code null}).
*/
public BiFunctionWithContext(ContextSnapshot snapshot, BiFunction<IN1, IN2, OUT> delegate, Consumer<ContextSnapshot> snapshotConsumer) {
super(snapshot, delegate, snapshotConsumer);
}

protected BiFunctionWithContext(Supplier<ContextSnapshot> supplier, BiFunction<IN1, IN2, OUT> delegate, Consumer<ContextSnapshot> consumer) {
super(supplier, delegate, consumer);
/**
* Protected constructor for use with a snapshot 'holder' object that acts as both snapshot supplier and -consumer.
*
* <p>
* This constructor is not for general use. Care must be taken to capture the context snapshot <em>before</em> the
* bi-function is called, otherwise the snapshot being reactivated would effectively update the context
* to the same values just captured.
*
* @param snapshotSupplier Supplier for the context snapshot that was previously captured.
* @param delegate The delegate bi-function to apply.
* @param snapshotConsumer Consumer accepting the resulting context snapshot after the delegate task ran
* (optional, may be {@code null}).
*/
protected BiFunctionWithContext(Supplier<ContextSnapshot> snapshotSupplier, BiFunction<IN1, IN2, OUT> delegate, Consumer<ContextSnapshot> snapshotConsumer) {
super(snapshotSupplier, delegate, snapshotConsumer);
}

/**
* Applies the delegate bi-function within reactivated context snapshot.
*
* <p>
* The implementation performs the following steps, in-order:
* <ol>
* <li>{@linkplain ContextSnapshot#reactivate() reactivate} the given snapshot
* <li>apply the delegate bi-function and get the result
* <li><em>if context snapshot consumer is non-null,</em>
* pass a {@linkplain ContextManagers#createContextSnapshot() new context snapshot} to the consumer
* <li>close the {@linkplain ContextSnapshot.Reactivation reactivation}
* <li>return the result</li>
* </ol>
*
* @param in1 the first argument to pass to the delegate bi-function.
* @param in2 the second argument to pass to the delegate bi-function.
* @return the result of the delegate bi-function.
* @throws RuntimeException if the delegate bi-function throws a runtime exception.
*/
@Override
public OUT apply(IN1 in1, IN2 in2) {
try (ContextSnapshot.Reactivation context = snapshot().reactivate()) {
Expand All @@ -64,6 +139,26 @@ public OUT apply(IN1 in1, IN2 in2) {
}
}

/**
* Constructs a new function that first the delegate bi-function within a reactivated context snapshot,
* and then applies the {@code after} function to its result, still within the reactivated context.
*
* <p>
* The implementation performs the following steps, in-order:
* <ol>
* <li>{@linkplain ContextSnapshot#reactivate() reactivate} the given snapshot
* <li>apply the delegate bi-function and get the result
* <li>apply the {@code after} function to the result to get the end result
* <li><em>if context snapshot consumer is non-null,</em>
* pass a {@linkplain ContextManagers#createContextSnapshot() new context snapshot} to the consumer
* <li>close the {@linkplain ContextSnapshot.Reactivation reactivation}
* <li>return the end result</li>
* </ol>
*
* @param after the function to apply to the result of this bi-function.
* @return a composed function that first applies this bi-function and then applies the after function,
* all within a reactivated context snapshot.
*/
@Override
public <V> BiFunction<IN1, IN2, V> andThen(Function<? super OUT, ? extends V> after) {
requireNonNull(after, "Cannot post-process bi-function with after function <null>.");
Expand Down
Loading

0 comments on commit c1f56d7

Please sign in to comment.