package org.codefx.libfx.concurrent.when; import java.util.Objects; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Predicate; import javafx.beans.value.ObservableValue; /** * <p> * Builder for {@link ExecuteAlwaysWhen} and {@link ExecuteOnceWhen}. * </p> * <h2>Example</h2>A typical use would look like this: * * <pre> * ObservableValue<State> workerState; * ExecuteWhen.on(workerState) * .when(state -> state == State.SUCCEEDED) * .thenOnce(state -> logSuccess()) * .executeWhen(); * </pre> * * @param <T> * the type the {@link ObservableValue} which will be observed by the constructed instance wraps */ public class ExecuteWhen<T> { // #begin FIELDS /** * The {@link ObservableValue} upon whose value the action's execution depends. */ private final ObservableValue<T> observable; /** * The condition the {@link #observable}'s value must fulfill for the action to be executed. */ private Optional<Predicate<? super T>> condition; // #end FIELDS // #begin CONSTRUCTION /** * Creates a new instance for the specified observable * * @param observable * the {@link ObservableValue} which will be observed by the created {@code Execute...When} instances */ private ExecuteWhen(ObservableValue<T> observable) { Objects.requireNonNull(observable, "The argument 'observable' must not be null."); this.observable = observable; condition = Optional.empty(); } /** * Creates a new builder. The built instance of {@code Execute...When} will observe the specified observable. * * @param <T> * the type the {@link ObservableValue} which will be observed by the constructed instance wraps * @param observable * the {@link ObservableValue} which will be observed by the created {@code Execute...When} instances * @return a new builder instance */ public static <T> ExecuteWhen<T> on(ObservableValue<T> observable) { return new ExecuteWhen<>(observable); } // #end CONSTRUCTION // #begin SETTING VALUES /** * Specifies the condition the observable's value must fulfill in order for the action to be executed. * * @param condition * the condition as a {@link Predicate} * @return this builder */ public ExecuteWhen<T> when(Predicate<? super T> condition) { Objects.requireNonNull(condition, "The argument 'condition' must not be null."); this.condition = Optional.of(condition); return this; } // #end SETTING VALUES // #begin BUILD /** * Creates an instance which: * <ul> * <li>observes the {@link ObservableValue} (specified for this builder's construction) for new values * <li>checks each new value against the condition set with {@link #when(Predicate)} (calling which is required) * <li>executes the specified {@code action} once if a value fulfills the condition * </ul> * Note that the observation does not start until {@link ExecuteOnceWhen#executeWhen()} is called. See * {@link ExecuteOnceWhen} for details. * * @param action * the {@link Consumer} of the value which passed the condition * @return an instance of {@link ExecuteOnceWhen} * @throws IllegalStateException * if {@link #when(Predicate)} was not called */ public ExecuteOnceWhen<T> thenOnce(Consumer<? super T> action) throws IllegalStateException { Objects.requireNonNull(action, "The argument 'action' must not be null."); ensureConditionWasSet(); return new ExecuteOnceWhen<T>(observable, condition.get(), action); } /** * Creates an instance which: * <ul> * <li>observes the {@link ObservableValue} (specified for this builder's construction) for new values * <li>checks each new value against the condition set with {@link #when(Predicate)} (calling which is required) * <li>executes the specified {@code action} every time a value fulfills the condition * </ul> * Note that the observation does not start until {@link ExecuteAlwaysWhen#executeWhen()} is called. See * {@link ExecuteAlwaysWhen} for details. * * @param action * the {@link Consumer} of the value which passed the condition * @return an instance of {@link ExecuteOnceWhen} * @throws IllegalStateException * if {@link #when(Predicate)} was not called */ public ExecuteAlwaysWhen<T> thenAlways(Consumer<? super T> action) throws IllegalStateException { Objects.requireNonNull(action, "The argument 'action' must not be null."); ensureConditionWasSet(); return new ExecuteAlwaysWhen<T>(observable, condition.get(), action); } /** * Makes sure that {@link #condition} was set, i.e. the {@link Optional} is not empty. * * @throws IllegalStateException * if {@link #condition} was not set */ private void ensureConditionWasSet() throws IllegalStateException { boolean noCondition = !condition.isPresent(); if (noCondition) throw new IllegalStateException( "Set a condition with 'when(Predicate<? super T>)' before calling any 'then...' method."); } // #end BUILD }