All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.reactfx.Await Maven / Gradle / Ivy

There is a newer version: 2.0-M5
Show newest version
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;

abstract class AwaitBase extends LazilyBoundStream implements AwaitingEventStream {
    private final EventStream source;
    private final Indicator pending = new Indicator();

    public AwaitBase(EventStream source) {
        this.source = source;
    }

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

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

    @Override
    protected final Subscription subscribeToInputs() {
        return source.subscribe(future -> {
            Guard g = pending.on();
            addCompletionHandler(future, (result, success) -> {
                if(success) {
                    emit(result);
                }
                g.close();
            });
        });
    }

    protected abstract void addCompletionHandler(F future, BiConsumer action);
}

class AwaitCompletionStage extends AwaitBase> {
    private final Executor clientThreadExecutor;

    public AwaitCompletionStage(
            EventStream> source,
            Executor clientThreadExecutor) {
        super(source);
        this.clientThreadExecutor = clientThreadExecutor;
    }

    @Override
    protected void addCompletionHandler(CompletionStage future, BiConsumer f) {
        future.whenCompleteAsync((result, error) -> {
            f.accept(result, error == null);
        }, clientThreadExecutor);
    }
}

class AwaitTask extends AwaitBase> {

    public AwaitTask(EventStream> source) {
        super(source);
    }

    @Override
    protected void addCompletionHandler(Task t, BiConsumer f) {
        t.addEventHandler(WORKER_STATE_SUCCEEDED, e -> f.accept(t.getValue(), true));
        t.addEventHandler(WORKER_STATE_FAILED, e -> f.accept(null, false));
        t.addEventHandler(WORKER_STATE_CANCELLED, e -> f.accept(null, false));
    }
}


abstract class AwaitLatestBase extends LazilyBoundStream implements AwaitingEventStream {
    private final EventStream source;

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

    private BooleanBinding pending = null;

    public AwaitLatestBase(EventStream source) {
        this.source = source;
    }

    @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() {
        return source.subscribe(future -> {
            long rev = replaceExpected(future);
            addResultHandler(future, t -> {
                if(rev == revision) {
                    emit(t);
                    setExpected(null);
                }
            });
            addErrorHandler(future, () -> {
                if(rev == revision) {
                    setExpected(null);
                }
            });
        });
    }

    private final long replaceExpected(F newExpected) {
        if(expectedFuture != null) {
            cancel(expectedFuture);
        }
        ++revision;
        setExpected(newExpected);
        return revision;
    }

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

    protected final void cancelExpected() {
        replaceExpected(null);
    }

    protected abstract void addResultHandler(F future, Consumer action);
    protected abstract void addErrorHandler(F future, Runnable action);
    protected abstract void cancel(F future);
}

class AwaitLatestCompletionStage extends AwaitLatestBase> {
    private final Executor clientThreadExecutor;

    public AwaitLatestCompletionStage(
            EventStream> source,
            Executor clientThreadExecutor) {
        super(source);
        this.clientThreadExecutor = clientThreadExecutor;
    }

    @Override
    protected void addResultHandler(CompletionStage future, Consumer f) {
        future.thenAcceptAsync(f, clientThreadExecutor);
    }

    @Override
    protected void addErrorHandler(CompletionStage future, Runnable action) {
        future.whenCompleteAsync((u, error) -> {
            if(error != null) {
                action.run();
            }
        }, clientThreadExecutor);
    }

    @Override
    protected void cancel(CompletionStage future) {
        // do nothing (cannot cancel a CompletionStage)
    }
}

class CancellableAwaitLatestCompletionStage extends AwaitLatestCompletionStage {
    private final EventStream canceller;

    public CancellableAwaitLatestCompletionStage(
            EventStream> source,
            EventStream canceller,
            Executor clientThreadExecutor) {
        super(source, clientThreadExecutor);
        this.canceller = canceller;
    }

    @Override
    protected Subscription subscribeToInputs() {
        Subscription s1 = super.subscribeToInputs();
        Subscription s2 = canceller.subscribe(x -> cancelExpected());
        return s1.and(s2);
    }
}

class AwaitLatestTask extends AwaitLatestBase> {
    public AwaitLatestTask(EventStream> source) {
        super(source);
    }

    @Override
    protected void addResultHandler(Task t, Consumer f) {
        t.addEventHandler(WORKER_STATE_SUCCEEDED, e -> f.accept(t.getValue()));
    }

    @Override
    protected void addErrorHandler(Task t, Runnable f) {
        t.addEventHandler(WORKER_STATE_FAILED, e -> f.run());
    }

    @Override
    protected void cancel(Task task) {
        task.cancel();
    }
}

class CancellableAwaitLatestTask extends AwaitLatestTask {
    private final EventStream canceller;

    public CancellableAwaitLatestTask(
            EventStream> source,
            EventStream canceller) {
        super(source);
        this.canceller = canceller;
    }

    @Override
    protected Subscription subscribeToInputs() {
        Subscription s1 = super.subscribeToInputs();
        Subscription s2 = canceller.subscribe(x -> cancelExpected());
        return s1.and(s2);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy