/**
 * 
 */
package com.github.phantomthief.failover.util;

import java.util.function.Predicate;

import com.github.phantomthief.failover.Failover;
import com.github.phantomthief.failover.exception.NoAvailableResourceException;
import com.github.phantomthief.util.ThrowableConsumer;
import com.github.phantomthief.util.ThrowableFunction;
import com.google.common.base.Throwables;
import com.google.common.reflect.Reflection;

/**
 * @author w.vela
 */
public class FailoverUtils {

    private FailoverUtils() {
        throw new UnsupportedOperationException();
    }

    public static <T, R, X extends Throwable> R run(Failover<T> failover,
            ThrowableFunction<T, R, X> func, Predicate<Throwable> failChecker) {
        T oneAvailable = failover.getOneAvailable();
        if (oneAvailable != null) {
            try {
                R result = func.apply(oneAvailable);
                failover.success(oneAvailable);
                return result;
            } catch (Throwable e) {
                if (failChecker == null || failChecker.test(e)) {
                    failover.fail(oneAvailable);
                } else {
                    failover.success(oneAvailable);
                }
                throw Throwables.propagate(e);
            }
        } else {
            throw new NoAvailableResourceException();
        }
    }

    public static <T, X extends Throwable> void call(Failover<T> failover,
            ThrowableConsumer<T, X> func, Predicate<Throwable> failChecker) {
        T oneAvailable = failover.getOneAvailable();
        if (oneAvailable != null) {
            try {
                func.accept(oneAvailable);
                failover.success(oneAvailable);
            } catch (Throwable e) {
                if (failChecker == null || failChecker.test(e)) {
                    failover.fail(oneAvailable);
                } else {
                    failover.success(oneAvailable);
                }
                throw Throwables.propagate(e);
            }
        } else {
            throw new NoAvailableResourceException();
        }
    }

    public static <T, E> T proxy(Class<T> iface, Failover<T> failover) {
        return proxy(iface, failover, null);
    }

    public static <T, E> T proxy(Class<T> iface, Failover<T> failover,
            Predicate<Throwable> failChecker) {
        return Reflection.newProxy(iface, (proxy, method, args) -> run(failover,
                res -> method.invoke(res, args), failChecker));
    }
}

@@ -89,16 +89,52 @@
 edicate;
+%0Aimport java.util.function.Supplier;
 %0A%0Aimport
@@ -2370,32 +2370,361 @@
  failChecker) %7B%0A
+        return proxy(iface, () -%3E failover, failChecker);%0A    %7D%0A%0A    public static %3CT, E%3E T proxy(Class%3CT%3E iface, Supplier%3CFailover%3CT%3E%3E failover) %7B%0A        return proxy(iface, failover, null);%0A    %7D%0A%0A    public static %3CT, E%3E T proxy(Class%3CT%3E iface, Supplier%3CFailover%3CT%3E%3E failover,%0A            Predicate%3CThrowable%3E failChecker) %7B%0A
         return R
@@ -2778,32 +2778,38 @@
  -%3E run(failover
+.get()
 ,%0A              

add supplier for proxy util.