Package org.reactfx

Source Code of org.reactfx.AwaitLatest

package org.reactfx;

import static javafx.concurrent.WorkerStateEvent.*;

import java.util.concurrent.CompletionStage;
import java.util.concurrent.Executor;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

import javafx.beans.binding.BooleanBinding;
import javafx.beans.value.ObservableBooleanValue;
import javafx.concurrent.Task;

import org.reactfx.util.TriConsumer;
import org.reactfx.util.Try;

class Await<T, F, R> extends LazilyBoundStream<R> implements AwaitingEventStream<R> {

    public static <T> AwaitingEventStream<T> awaitCompletionStage(
            EventStream<CompletionStage<T>> source,
            Executor clientThreadExecutor) {
        return new Await<>(
                source,
                (future, handler) -> addCompletionHandler(future, handler, clientThreadExecutor),
                reportingEmitter());
    }

    public static <T> AwaitingEventStream<Try<T>> tryAwaitCompletionStage(
            EventStream<CompletionStage<T>> source,
            Executor clientThreadExecutor) {
        return new Await<>(
                source,
                (future, handler) -> addCompletionHandler(future, handler, clientThreadExecutor),
                tryEmitter());
    }

    public static <T> AwaitingEventStream<T> awaitTask(
            EventStream<Task<T>> source) {
        return new Await<>(source, Await::addCompletionHandler, reportingEmitter());
    }

    public static <T> AwaitingEventStream<Try<T>> tryAwaitTask(
            EventStream<Task<T>> source) {
        return new Await<>(source, Await::addCompletionHandler, tryEmitter());
    }

    static <T> void addCompletionHandler(
            CompletionStage<T> future,
            TriConsumer<T, Throwable, Boolean> handler,
            Executor executor) {
        future.whenCompleteAsync((result, error) -> {
            handler.accept(result, error, false);
        }, executor);
    }

    static <T> void addCompletionHandler(
            Task<T> t,
            TriConsumer<T, Throwable, Boolean> handler) {
        t.addEventHandler(WORKER_STATE_SUCCEEDED, e -> handler.accept(t.getValue(), null, false));
        t.addEventHandler(WORKER_STATE_FAILED, e -> handler.accept(null, t.getException(), false));
        t.addEventHandler(WORKER_STATE_CANCELLED, e -> handler.accept(null, null, true));
    }

    static <T> TriConsumer<LazilyBoundStream<T>, T, Throwable> reportingEmitter() {
        return (stream, value, error) -> {
            if(error == null) {
                stream.emit(value);
            } else {
                stream.reportError(error);
            }
        };
    }

    static <T> TriConsumer<LazilyBoundStream<Try<T>>, T, Throwable> tryEmitter() {
        return (stream, value, error) -> {
            if(error == null) {
                stream.emit(Try.success(value));
            } else {
                stream.emit(Try.failure(error));
            }
        };
    }

    private final EventStream<F> source;
    private final Indicator pending = new Indicator();
    private final BiConsumer<F, TriConsumer<T, Throwable, Boolean>> addCompletionHandler;
    private final TriConsumer<LazilyBoundStream<R>, T, Throwable> emitter;

    private Await(
            EventStream<F> source,
            BiConsumer<F, TriConsumer<T, Throwable, Boolean>> addCompletionHandler,
            TriConsumer<LazilyBoundStream<R>, T, Throwable> emitter) {
        this.source = source;
        this.addCompletionHandler = addCompletionHandler;
        this.emitter = emitter;
    }

    @Override
    public final ObservableBooleanValue pendingProperty() {
        return pending;
    }

    @Override
    public final boolean isPending() {
        return pending.isOn();
    }

    @Override
    protected final Subscription subscribeToInputs() {
        return subscribeTo(source, future -> {
            Guard g = pending.on();
            addCompletionHandler.accept(future, (result, error, cancelled) -> {
                if(!cancelled) {
                    emitter.accept(this, result, error);
                }
                g.close();
            });
        });
    }
}


class AwaitLatest<T, F, R> extends LazilyBoundStream<R> implements AwaitingEventStream<R> {

    public static <T> AwaitingEventStream<T> awaitCompletionStage(
            EventStream<CompletionStage<T>> source,
            Executor clientThreadExecutor) {
        return new AwaitLatest<>(
                source,
                EventStreams.never(), // no cancel impulse
                future -> {}, // cannot cancel a CompletionStage
                (future, handler) -> Await.addCompletionHandler(future, handler, clientThreadExecutor),
                Await.reportingEmitter());
    }

    public static <T> AwaitingEventStream<Try<T>> tryAwaitCompletionStage(
            EventStream<CompletionStage<T>> source,
            Executor clientThreadExecutor) {
        return new AwaitLatest<>(
                source,
                EventStreams.never(), // no cancel impulse
                future -> {}, // cannot cancel a CompletionStage
                (future, handler) -> Await.addCompletionHandler(future, handler, clientThreadExecutor),
                Await.tryEmitter());
    }

    public static <T> AwaitingEventStream<T> awaitTask(
            EventStream<Task<T>> source) {
        return new AwaitLatest<>(
                source,
                EventStreams.never(), // no cancel impulse
                Task::cancel,
                Await::addCompletionHandler,
                Await.reportingEmitter());
    }

    public static <T> AwaitingEventStream<Try<T>> tryAwaitTask(
            EventStream<Task<T>> source) {
        return new AwaitLatest<>(
                source,
                EventStreams.never(), // no cancel impulse
                Task::cancel,
                Await::addCompletionHandler,
                Await.tryEmitter());
    }

    public static <T> AwaitingEventStream<T> awaitCompletionStage(
            EventStream<CompletionStage<T>> source,
            EventStream<?> cancelImpulse,
            Executor clientThreadExecutor) {
        return new AwaitLatest<>(
                source,
                cancelImpulse,
                future -> {}, // cannot cancel a CompletionStage
                (future, handler) -> Await.addCompletionHandler(future, handler, clientThreadExecutor),
                Await.reportingEmitter());
    }

    public static <T> AwaitingEventStream<Try<T>> tryAwaitCompletionStage(
            EventStream<CompletionStage<T>> source,
            EventStream<?> cancelImpulse,
            Executor clientThreadExecutor) {
        return new AwaitLatest<>(
                source,
                cancelImpulse,
                future -> {}, // cannot cancel a CompletionStage
                (future, handler) -> Await.addCompletionHandler(future, handler, clientThreadExecutor),
                Await.tryEmitter());
    }

    public static <T> AwaitingEventStream<T> awaitTask(
            EventStream<Task<T>> source,
            EventStream<?> cancelImpulse) {
        return new AwaitLatest<>(
                source,
                cancelImpulse,
                Task::cancel,
                Await::addCompletionHandler,
                Await.reportingEmitter());
    }

    public static <T> AwaitingEventStream<Try<T>> tryAwaitTask(
            EventStream<Task<T>> source,
            EventStream<?> cancelImpulse) {
        return new AwaitLatest<>(
                source,
                cancelImpulse,
                Task::cancel,
                Await::addCompletionHandler,
                Await.tryEmitter());
    }

    private final EventStream<F> source;
    private final EventStream<?> cancelImpulse;
    private final Consumer<F> canceller;
    private final BiConsumer<F, TriConsumer<T, Throwable, Boolean>> addCompletionHandler;
    private final TriConsumer<LazilyBoundStream<R>, T, Throwable> emitter;

    private long revision = 0;
    private F expectedFuture = null;

    private BooleanBinding pending = null;

    private AwaitLatest(
            EventStream<F> source,
            EventStream<?> cancelImpulse,
            Consumer<F> canceller,
            BiConsumer<F, TriConsumer<T, Throwable, Boolean>> addCompletionHandler,
            TriConsumer<LazilyBoundStream<R>, T, Throwable> emitter) {
        this.source = source;
        this.cancelImpulse = cancelImpulse;
        this.canceller = canceller;
        this.addCompletionHandler = addCompletionHandler;
        this.emitter = emitter;
    }

    @Override
    public ObservableBooleanValue pendingProperty() {
        if(pending == null) {
            pending = new BooleanBinding() {
                @Override
                protected boolean computeValue() {
                    return expectedFuture != null;
                }
            };
        }
        return pending;
    }

    @Override
    public boolean isPending() {
        return pending != null ? pending.get() : expectedFuture != null;
    }

    @Override
    protected Subscription subscribeToInputs() {
        Subscription s1 = subscribeTo(source, future -> {
            long rev = replaceExpected(future);
            addCompletionHandler.accept(future, (result, error, cancelled) -> {
                if(rev == revision) {
                    if(!cancelled) {
                        emitter.accept(this, result, error); // emit before setting pending to false
                    }
                    setExpected(null);
                }
            });
        });

        Subscription s2 = subscribeTo(cancelImpulse, x -> replaceExpected(null));

        return s1.and(s2);
    }

    private final long replaceExpected(F newExpected) {
        ++revision; // increment before cancelling, so that the cancellation handler is not executed
        if(expectedFuture != null) {
            canceller.accept(expectedFuture);
        }
        setExpected(newExpected);
        return revision;
    }

    private void setExpected(F newExpected) {
        expectedFuture = newExpected;
        if(pending != null) {
            pending.invalidate();
        }
    }
}
TOP

Related Classes of org.reactfx.AwaitLatest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.