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

io.vertx.up.unity.Fluctuate Maven / Gradle / Ivy

There is a newer version: 0.9.0
Show newest version
package io.vertx.up.unity;

import io.reactivex.Observable;
import io.vertx.core.AsyncResult;
import io.vertx.core.CompositeFuture;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.up.exception.WebException;
import io.vertx.up.exception.web._500InternalServerException;
import io.vertx.up.util.Ut;

import java.util.*;
import java.util.function.*;

@SuppressWarnings("unchecked")
class Fluctuate {
    /**
     * Source -> List -> List>
     */
    static  Future> thenParallel(
            final Future> source,
            final Function> generateFun,
            final BiFunction mergeFun
    ) {
        return source.compose(first -> {
            final List secondFutures = new ArrayList<>();
            Observable.fromIterable(first)
                    .map(generateFun::apply)
                    .filter(Objects::nonNull)
                    .subscribe(secondFutures::add)
                    .dispose();
            final Future> result = Future.future();
            CompositeFuture.all(secondFutures).setHandler(res -> {
                final List secondary = res.result().list();
                // Zipper Operation, the base list is first.
                final List completed = Ut.elementZip(first, secondary, mergeFun);
                result.complete(completed);
            });
            return result;
        });
    }

    static Future thenScatterJson(
            final Future source,
            final Function> generateFun,
            final BiFunction mergeFun
    ) {
        return source.compose(first -> {
            final List secondFutures = new ArrayList<>();
            Observable.fromIterable(first)
                    .map(item -> (JsonObject) item)
                    .map(generateFun::apply)
                    .subscribe(secondFutures::add)
                    .dispose();
            final Future result = Future.future();
            CompositeFuture.all(secondFutures).setHandler(res -> {
                final List secondary = res.result().list();
                // Zipper Operation, the base list is first
                final List completed = Ut.elementZip(first.getList(), secondary, mergeFun);
                result.complete(new JsonArray(completed));
            });
            return result;
        });
    }

    static Future thenParallelArray(
            final Future source,
            final Function> generateFun,
            final BinaryOperator operatorFun
    ) {
        return source.compose(first -> {
            final List secondFutures = new ArrayList<>();
            Observable.fromIterable(first)
                    .map(item -> (JsonObject) item)
                    .map(generateFun::apply)
                    .subscribe(secondFutures::add)
                    .dispose();
            final Future result = Future.future();
            CompositeFuture.all(secondFutures).setHandler(res -> {
                final List secondary = res.result().list();
                // Zipper Operation, the base list is first
                final List completed = Ut.elementZip(first.getList(), secondary, operatorFun);
                result.complete(new JsonArray(completed));
            });
            return result;
        });
    }

    static Future thenParallelArray(
            final Future... futures
    ) {
        final Future result = Future.future();
        CompositeFuture.all(Arrays.asList(futures)).setHandler(res -> {
            final JsonObject resultMap = new JsonObject();
            Ut.itList(res.result().list(), (item, index) -> resultMap.put(index.toString(), item));
            result.complete(resultMap);
        });
        return result;
    }

    static Future thenParallelJson(
            final Future... futures
    ) {
        final Future result = Future.future();
        // thenResponse
        CompositeFuture.all(Arrays.asList(futures)).setHandler(thenResponse(result, (finished) -> {
            final JsonObject resultMap = new JsonObject();
            if (null != finished) {
                Ut.itList(finished.list(), (item, index) -> resultMap.put(index.toString(), item));
            }
            return resultMap;
        }));
        return result;
    }

    static Future thenParallelJson(
            final Future source,
            final Function> generateFun,
            final BiConsumer... operatorFun
    ) {
        return source.compose(first -> {
            final List secondFutures = generateFun.apply(first);
            final Future result = Future.future();
            // thenResponse
            CompositeFuture.all(secondFutures).setHandler(thenResponse(result, (finished) -> {
                if (null != finished) {
                    final List secondary = finished.list();
                    // Zipper Operation, the base list is first
                    Ut.itList(secondary, (item, index) -> operatorFun[index].accept(first, item));
                }
                return first;
            }));
            return result;
        });
    }

    /**
     * Source ->
     * Target1
     * Target2
     */
    static  Future thenComposite(
            final Future source,
            final BiFunction, T> mergeFun,
            final Supplier>... suppliers) {
        return source.compose(first -> {
            final List secondFutures = new ArrayList<>();
            Observable.fromArray(suppliers)
                    .map(Supplier::get)
                    .subscribe(secondFutures::add)
                    .dispose();
            // thenResponse
            return thenResponse(secondFutures, first, mergeFun);
        });
    }

    static Future thenComposite(
            final List> futures
    ) {
        final Future result = Future.future();
        final List converted = new ArrayList<>(futures);
        // thenResponse
        CompositeFuture.all(converted).setHandler(thenResponse(result, (finished) ->
                null == finished ? new JsonArray() : new JsonArray(finished.list())
        ));
        return result;
    }

    static  Future thenComposite(
            final Future source,
            final BiFunction, T> mergeFun,
            final Function>... functions) {
        return source.compose(first -> {
            final List secondFutures = new ArrayList<>();
            Observable.fromArray(functions)
                    .map(item -> item.apply(first))
                    .subscribe(secondFutures::add)
                    .dispose();
            // thenResponse
            return thenResponse(secondFutures, first, mergeFun);
        });
    }

    static  Future thenOtherwise(
            final Future conditionFuture,
            final Supplier> supplierTrue, final Function trueFun,
            final Supplier> supplierFalse, final Function falseFun
    ) {
        final Future future = Future.future();
        conditionFuture.setHandler(handler -> {
            if (handler.succeeded() && handler.result()) {
                // Success & Boolean
                final Future trueFuture = supplierTrue.get();
                trueFuture.setHandler(trueRes -> future.complete(trueFun.apply(trueRes.result())));
            } else {
                // Failed & Boolean = false;
                final Future falseFuture = supplierFalse.get();
                falseFuture.setHandler(falseRes -> future.complete(falseFun.apply(falseRes.result())));
            }
        });
        return future;
    }

    static  Future thenOtherwise(
            final Future conditionFuture,
            final Supplier> supplierTrue, final Function trueFun,
            final Class clazz, final Object... args
    ) {
        final Future future = Future.future();
        conditionFuture.setHandler(handler -> {
            if (handler.succeeded() && handler.result()) {
                // Success & Boolean
                final Future trueFuture = supplierTrue.get();
                trueFuture.setHandler(trueRes -> future.complete(trueFun.apply(trueRes.result())));
            } else {
                // Failed & Boolean = false;
                if (null == clazz) {
                    future.complete();
                } else {
                    // Error existing
                    final WebException error = Ut.instance(clazz, args);
                    future.fail(error);
                }
            }
        });
        return future;
    }

    static  Future thenError(
            final Class clazz,
            final Object... args
    ) {
        final WebException error = To.toError(clazz, args);
        return Future.failedFuture(error);
    }

    private static  Future thenResponse(
            final List secondFutures,
            final F first,
            final BiFunction, T> mergeFun) {
        final Future result = Future.future();
        CompositeFuture.all(secondFutures).setHandler(
                thenResponse(result, (finished) -> null == finished ? null : mergeFun.apply(first, finished.list())));
        return result;
    }


    static  Future> thenSet(
            final List data,
            final Function> fun
    ) {
        final Future> results = Future.future();
        final List futures = new ArrayList<>();
        data.stream().map(fun).forEach(futures::add);
        CompositeFuture.all(futures).setHandler(thenResponse(results, finished -> {
            if (null == finished) {
                return new HashSet<>();
            } else {
                final List extracted = finished.list();
                return new HashSet<>(extracted);
            }
        }));
        return results;
    }


    private static  Handler> thenResponse(
            final Future future,
            final Function fun) {
        return res -> {
            if (res.succeeded()) {
                final T callback = fun.apply(res.result());
                future.complete(callback);
            } else {
                if (null != res.cause()) {
                    res.cause().printStackTrace();
                    future.fail(res.cause());
                } else {
                    future.fail(new _500InternalServerException(Fluctuate.class, null));
                }
            }
        };
    }
}