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

com.github.phantomthief.failover.impl.ComboFailover Maven / Gradle / Ivy

package com.github.phantomthief.failover.impl;

import static com.github.phantomthief.tuple.Tuple.tuple;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Multimaps.toMultimap;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import javax.annotation.CheckReturnValue;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;

import com.github.phantomthief.failover.Failover;
import com.github.phantomthief.tuple.TwoTuple;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;

/**
 * @author w.vela
 * Created on 2017-12-28.
 */
public class ComboFailover implements Failover, Iterable> {

    private final List> failoverList;
    private final boolean recheckOnMiss;

    private volatile Multimap> mapByObject;

    private ComboFailover(ComboFailoverBuilder builder) {
        this.failoverList = builder.list;
        this.recheckOnMiss = builder.recheckOnMiss;
        mapByObject = groupByObjects();
    }

    public static  ComboFailoverBuilder builder() {
        return new ComboFailoverBuilder<>();
    }

    private HashMultimap> groupByObjects() {
        return failoverList.stream()
                .flatMap(failover -> failover.getAll().stream()
                        .map(it -> tuple(it, failover)))
                .collect(toMultimap(TwoTuple::getFirst, TwoTuple::getSecond, HashMultimap::create));
    }

    @Override
    public List getAll() {
        return failoverList.stream()
                .map(Failover::getAll)
                .flatMap(List::stream)
                .collect(toList());
    }

    @Nullable
    @Override
    public T getOneAvailableExclude(Collection exclusions) {
        return failoverList.stream()
                .map(failover -> failover.getOneAvailableExclude(exclusions))
                .filter(Objects::nonNull)
                .findAny()
                .orElse(null);
    }

    @Override
    public List getAvailableExclude(Collection exclusions) {
        return failoverList.stream()
                .map(failover -> failover.getAvailableExclude(exclusions))
                .flatMap(List::stream)
                .collect(toList());
    }

    @Nullable
    @Override
    public T getOneAvailable() {
        return failoverList.stream()
                .map(Failover::getOneAvailable)
                .filter(Objects::nonNull)
                .findAny()
                .orElse(null);
    }

    @Override
    public List getAvailable(int n) {
        return failoverList.stream()
                .map(failover -> failover.getAvailable(n))
                .flatMap(List::stream)
                .limit(n)
                .collect(toList());
    }

    @Override
    public void fail(@Nonnull T object) {
        getByObject(object).forEach(failover -> failover.fail(object));
    }

    @Override
    public void down(@Nonnull T object) {
        getByObject(object).forEach(failover -> failover.down(object));
    }

    @Override
    public List getAvailable() {
        return failoverList.stream()
                .map(Failover::getAvailable)
                .flatMap(List::stream)//
                .collect(toList());
    }

    @Override
    public Set getFailed() {
        return failoverList.stream()
                .map(Failover::getFailed)
                .flatMap(Set::stream)
                .collect(toSet());
    }

    @Override
    public void success(@Nonnull T object) {
        getByObject(object).forEach(failover -> failover.success(object));
    }

    private Collection> getByObject(T object) {
        Collection> list = mapByObject.get(object);
        if (recheckOnMiss && list.isEmpty()) { // surely it's wrong. build it again.
            mapByObject = groupByObjects();
            list = mapByObject.get(object);
        }
        return list;
    }

    @Override
    public Iterator> iterator() {
        return failoverList.iterator();
    }

    @NotThreadSafe
    public static class ComboFailoverBuilder {

        private final List> list = new ArrayList<>();
        private boolean recheckOnMiss;

        private ComboFailoverBuilder() {
        }

        @CheckReturnValue
        @Nonnull
        public ComboFailoverBuilder add(@Nonnull Failover failover) {
            list.add(checkNotNull(failover));
            return this;
        }

        @CheckReturnValue
        @Nonnull
        public ComboFailoverBuilder
                addAll(@Nonnull Collection> failoverList) {
            list.addAll(checkNotNull(failoverList));
            return this;
        }

        @CheckReturnValue
        @Nonnull
        public ComboFailoverBuilder recheckOnMiss(boolean value) {
            recheckOnMiss = value;
            return this;
        }

        @Nonnull
        public ComboFailover build() {
            return new ComboFailover<>(this);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy