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

io.vlingo.common.completes.SinkAndSourceBasedCompletes Maven / Gradle / Ivy

There is a newer version: 1.7.5
Show newest version
// Copyright © 2012-2020 VLINGO LABS. All rights reserved.
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL
// was not distributed with this file, You can obtain
// one at https://mozilla.org/MPL/2.0/.

package io.vlingo.common.completes;

import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;

import io.vlingo.common.Completes;
import io.vlingo.common.Scheduler;
import io.vlingo.common.completes.operations.AndThen;
import io.vlingo.common.completes.operations.AndThenConsume;
import io.vlingo.common.completes.operations.AndThenToSource;
import io.vlingo.common.completes.operations.FailureGateway;
import io.vlingo.common.completes.operations.Otherwise;
import io.vlingo.common.completes.operations.OtherwiseConsume;
import io.vlingo.common.completes.operations.Recover;
import io.vlingo.common.completes.operations.TimeoutGateway;
import io.vlingo.common.completes.sinks.InMemorySink;
import io.vlingo.common.completes.sources.InMemorySource;

public class SinkAndSourceBasedCompletes implements Completes {
    private static final long DEFAULT_TIMEOUT = Long.MAX_VALUE;

    private final Scheduler scheduler;
    public final Source source;
    private final Source currentOperation;
    private final Sink sink;

    protected SinkAndSourceBasedCompletes(Scheduler scheduler, Source source, Source currentOperation, Sink sink) {
        this.scheduler = scheduler;
        this.source = source;
        this.sink = sink;
        this.currentOperation = currentOperation;
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    protected SinkAndSourceBasedCompletes(Scheduler scheduler) {
        this.scheduler = scheduler;
        this.source = new InMemorySource<>();
        this.sink = new InMemorySink<>();
        this.currentOperation = (Source) source;

        source.subscribe((Sink) sink);
    }

    @SuppressWarnings("unchecked")
    public static  SinkAndSourceBasedCompletes withScheduler(Scheduler scheduler) {
        InMemorySource source = new InMemorySource<>();
        InMemorySink sink = new InMemorySink<>();

        source.subscribe(sink);

        return new SinkAndSourceBasedCompletes<>(scheduler, (Source) source, source, sink);
    }

    public static boolean isToggleActive() {
        return Boolean.parseBoolean(System.getProperty("vlingo.InMemoryCompletes", "false"));
    }

    @Override
    @SuppressWarnings("unchecked")
    public  Completes andThen(long timeout, O failedOutcomeValue, Function function) {
        FailureGateway failureGateway = new FailureGateway<>(failedOutcomeValue);
        TimeoutGateway timeoutGateway = new TimeoutGateway<>(scheduler, timeout);
        Operation newSource = new AndThen<>(function);
        currentOperation.subscribe(timeoutGateway);
        timeoutGateway.subscribe(newSource);
        newSource.subscribe(failureGateway);
        failureGateway.subscribe((InMemorySink) sink);

        return new SinkAndSourceBasedCompletes<>(scheduler, source, failureGateway, (InMemorySink) sink);
    }

    @Override
    public  Completes andThen(O failedOutcomeValue, Function function) {
        return andThen(DEFAULT_TIMEOUT, failedOutcomeValue, function);
    }

    @Override
    public  Completes andThen(long timeout, Function function) {
        return andThen(timeout, null, function);
    }

    @Override
    public  Completes andThen(Function function) {
        return andThen(DEFAULT_TIMEOUT, null, function);
    }

    @Override
    public Completes andThenConsume(long timeout, T failedOutcomeValue, Consumer consumer) {
        FailureGateway failureGateway = new FailureGateway<>(failedOutcomeValue);
        TimeoutGateway timeoutGateway = new TimeoutGateway<>(scheduler, timeout);
        Operation newSource = new AndThenConsume<>(consumer);
        currentOperation.subscribe(timeoutGateway);
        timeoutGateway.subscribe(newSource);
        newSource.subscribe(failureGateway);
        failureGateway.subscribe(sink);

        return new SinkAndSourceBasedCompletes(scheduler, source, failureGateway, sink);
    }

    @Override
    public Completes andThenConsume(T failedOutcomeValue, Consumer consumer) {
        return andThenConsume(DEFAULT_TIMEOUT, failedOutcomeValue, consumer);
    }

    @Override
    public Completes andThenConsume(long timeout, Consumer consumer) {
        return andThenConsume(timeout, null, consumer);
    }

    @Override
    public Completes andThenConsume(Consumer consumer) {
        return andThenConsume(DEFAULT_TIMEOUT, null, consumer);
    }

    @Override
    @SuppressWarnings("unchecked")
    public  O andThenTo(long timeout, F failedOutcomeValue, Function function) {
        FailureGateway failureGateway = new FailureGateway<>((O) failedOutcomeValue);
        TimeoutGateway timeoutGateway = new TimeoutGateway<>(scheduler, timeout);
        Operation newSource = new AndThenToSource<>(function.andThen(e -> (Completes) e).andThen(InMemorySource::fromCompletes));

        currentOperation.subscribe(timeoutGateway);
        timeoutGateway.subscribe(newSource);
        newSource.subscribe(failureGateway);
        failureGateway.subscribe((InMemorySink) sink);

        return (O) new SinkAndSourceBasedCompletes<>(scheduler, source, failureGateway, (InMemorySink) sink);
    }

    @Override
    public  O andThenTo(F failedOutcomeValue, Function function) {
        return andThenTo(DEFAULT_TIMEOUT, failedOutcomeValue, function);
    }

    @Override
    public  O andThenTo(long timeout, Function function) {
        return andThenTo(timeout, null, function);
    }

    @Override
    public  O andThenTo(Function function) {
        return andThenTo(DEFAULT_TIMEOUT, null, function);
    }

    @Override
    public Completes otherwise(Function function) {
        Operation otherwise = new Otherwise<>(function);
        currentOperation.subscribe(otherwise);
        otherwise.subscribe(sink);

        return new SinkAndSourceBasedCompletes<>(scheduler, source, otherwise, sink);
    }

    @Override
    public Completes otherwiseConsume(Consumer consumer) {
        Operation otherwise = new OtherwiseConsume<>(consumer);
        currentOperation.subscribe(otherwise);
        otherwise.subscribe(sink);

        return new SinkAndSourceBasedCompletes<>(scheduler, source, otherwise, sink);
    }

    @Override
    public Completes recoverFrom(Function function) {
        Operation newSource = new Recover<>(function);
        currentOperation.subscribe(newSource);
        newSource.subscribe(sink);

        return new SinkAndSourceBasedCompletes<>(scheduler, source, newSource, sink);
    }

    @Override
    public  O await() {
        return await(DEFAULT_TIMEOUT);
    }

    @Override
    @SuppressWarnings("unchecked")
    public  O await(long timeout) {
        source.activate();

        try {
            Optional value = sink.await(timeout);
            if (value.isPresent()) {
                return (O) value.get();
            }

        } catch (Exception e) {
            return null;
        }

        return null;
    }

    @Override
    public boolean isCompleted() {
        return sink.hasBeenCompleted();
    }

    @Override
    public boolean hasFailed() {
        return sink.hasFailed();
    }

    @Override
    public void failed() {
        source.emitError(new IllegalStateException("Forced failure in Completes"));
    }

    @Override
    public boolean hasOutcome() {
        return sink.hasOutcome();
    }

    @Override
    public T outcome() {
        return await();
    }

    @Override
    public Completes repeat() {
        sink.repeat();
        return this;
    }

    @Override
    @SuppressWarnings("unchecked")
    public  Completes andFinally() {
      return andFinally(value -> (O) value);
    }

    @Override
    public  Completes andFinally(final Function function) {
        final Completes edge = andThen(function);
        source.activate();
        return edge;
    }

    @Override
    public void andFinallyConsume(Consumer consumer) {
        andThenConsume(consumer);
        source.activate();
    }

    @Override
    @SuppressWarnings("unchecked")
    public  Completes with(O outcome) {
        source.emitOutcome(outcome);
        return (SinkAndSourceBasedCompletes) this;
    }

    @Override
    public String toString() {
        return "SinkAndSourceBasedCompletes{" +
                "scheduler=" + scheduler +
                ", source=" + source +
                ", currentOperation=" + currentOperation +
                ", sink=" + sink +
                '}';
    }
}