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

net.e6tech.elements.network.cluster.catalyst.Catalyst Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2015-2019 Futeh Kao
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.e6tech.elements.network.cluster.catalyst;

import net.e6tech.elements.common.util.SystemException;
import net.e6tech.elements.common.util.concurrent.Async;
import net.e6tech.elements.common.federation.Registry;
import net.e6tech.elements.network.cluster.catalyst.dataset.*;
import net.e6tech.elements.network.cluster.catalyst.scalar.Scalar;
import net.e6tech.elements.network.cluster.catalyst.transform.Series;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Function;

@SuppressWarnings({"unchecked", "squid:S00119", "squid:S1700"})
public class Catalyst {
    private Registry registry;
    private long waitTime = 30000L;
    private String qualifier = "";
    private Class reactorClass;

    public Catalyst(String qualifier, Class reactorClass,  Registry registry) {
        this.qualifier = qualifier;
        this.registry = registry;
        this.reactorClass = reactorClass;
    }

    public long getWaitTime() {
        return waitTime;
    }

    public void setWaitTime(long waitTime) {
        this.waitTime = waitTime;
    }

    public String getQualifier() {
        return qualifier;
    }

    public Registry getRegistry() {
        return registry;
    }

    public  Builder builder(DataSet dataSet) {
        return new Builder<>(this, dataSet);
    }

    public  Builder builder(Series series, DataSet dataSet) {
        return new Builder<>(this, series, dataSet);
    }

    public  U scalar(Scalar scalar, DataSet dataSet) {
        Collection result = collect(scalar, dataSet);
        Async async = registry.async(qualifier, reactorClass, waitTime, Registry.Routing.local);
        Series emptySeries = new Series<>();
        Scalar copy;
        try {
            List> segList = new ArrayList<>();
            segList.add(reactor -> result.stream());
            Segments segments = new Segments<>(this, segList);
            copy = (Scalar) scalar.gatherer();
            copy.setSeries(emptySeries.allocate(segments));
        } catch (Exception e) {
            throw new SystemException(e);
        }

        return async.apply(p -> p.apply(copy))
                .toCompletableFuture().join();
    }

    public  Collection collect(Scalar scalar, DataSet dataSet) {
        List> workLoad = prepareWork(dataSet,
                segments -> {
                    try {
                        Scalar copy = scalar.clone();
                        copy.setSeries(scalar.getSeries().allocate(segments));
                        return copy;
                    } catch (Exception e) {
                        throw new SystemException(e);
                    }
                });
        List result = new ArrayList<>();
        for (Work work: workLoad) {
            work.start();
        }
        for (Work work: workLoad) {
            result.add(work.value());
        }
        return result;
    }

    @SuppressWarnings("squid:S1596")
    public void run(Runnable ... runnables) {
        RemoteDataSet dataSet = new RemoteDataSet<>();
        for (Runnable runnable : runnables)
            dataSet.add(reactor -> {
                runnable.run();
                return Collections.EMPTY_LIST.stream();
            });
        transform(new Series<>(), dataSet);
    }

    @SuppressWarnings("squid:S1596")
    public void run(Consumer ... consumers) {
        RemoteDataSet dataSet = new RemoteDataSet<>();
        for (Consumer consumer : consumers)
            dataSet.add(reactor -> {
                consumer.accept(reactor);
                return Collections.EMPTY_LIST.stream();
            });
        transform(new Series<>(), dataSet);
    }

    public  Collection transform(Series series, DataSet dataSet) {
        List>> workLoad =
                prepareWork(dataSet, series::allocate);
        for (Work> work: workLoad) {
            work.start();
        }

        Gatherer gatherer = series.gatherer();
        for (Work> work: workLoad) {
            gatherer.gather(work.value());
        }
        return gatherer.collection;
    }

    private  List> prepareWork(DataSet dataSet, Function, SerializableFunction> work) {
        Segments segments = dataSet.segment(this);
        List> workLoad = new ArrayList<>();
        for (int i = 0; i < segments.size(); i++) {
            workLoad.add(new Work(registry.async(qualifier, reactorClass, waitTime), segments, work));
        }
        return workLoad;
    }

    private static class Work {
        Async async;
        Segments segments;
        CompletableFuture future;
        Function, SerializableFunction> work;
        SerializableFunction function;

        Work(Async async, Segments segments, Function, SerializableFunction> work) {
            this.async = async;
            this.segments = segments;
            this.work = work;
        }

        void start() {
            if (function == null) {
                // this will create a Series, Scalar or other Function for submiting to Reactor
                // the result should contain a segment removed from segments.  Therefore, work.apply should only be called once.
                function = work.apply(segments);
            }
            future = async.apply(reactor -> reactor.apply(function)).toCompletableFuture();
        }

        R value() {
            try {
                return future.join();
            } catch (Exception ex) {
                start();
                return future.join();
            }
        }
    }
}