// Path: core/src/main/java/com/bazaarvoice/ostrich/PartitionContext.java
// public interface PartitionContext {
//     /**
//      * Gets the default piece of context. In many cases, there is only a single piece of relevant context, which this
//      * method should provide.
//      *
//      * @return The default context data.
//      */
//     Object get();
// 
//     /**
//      * Gets the context for the specified key.
//      * @param key The key for the desired context data.
//      * @return The context data.
//      */
//     Object get(String key);
// 
//     /**
//      * Gets a {@code Map} version of the context. The Map should be immutable.
//      * @return A {@code Map} with the same key/value pairs as this context.
//      */
//     Map<String, Object> asMap();
// }
// 
// Path: core/src/main/java/com/bazaarvoice/ostrich/exceptions/NoAvailableHostsException.java
// public class NoAvailableHostsException extends DiscoveryException {
//     private static final long serialVersionUID = 0;
// 
//     public NoAvailableHostsException() {
//         super();
//     }
// 
//     public NoAvailableHostsException(String message) {
//         super(message);
//     }
// 
//     public NoAvailableHostsException(String message, Throwable cause) {
//         super(message, cause);
//     }
// 
//     public NoAvailableHostsException(Throwable cause) {
//         super(cause);
//     }
// }


import com.bazaarvoice.ostrich.PartitionContext;
import com.bazaarvoice.ostrich.RetryPolicy;
import com.bazaarvoice.ostrich.ServiceCallback;
import com.bazaarvoice.ostrich.ServiceEndPoint;
import com.bazaarvoice.ostrich.ServiceEndPointPredicate;
import com.bazaarvoice.ostrich.exceptions.MaxRetriesException;
import com.bazaarvoice.ostrich.exceptions.NoAvailableHostsException;
import com.bazaarvoice.ostrich.metrics.Metrics;
import com.codahale.metrics.Histogram;
import com.codahale.metrics.Meter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import com.google.common.base.Ticker;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import static com.google.common.base.Preconditions.checkNotNull;
            @Override
            public R call() throws Exception {
                return _pool.execute(retryPolicy, callback);
            }
        });
    }

    @Override
    public <R> Future<R> execute(final PartitionContext partitionContext, final RetryPolicy retryPolicy,
                                 final ServiceCallback<S, R> callback) {
        return _executor.submit(new Callable<R>() {
            @Override
            public R call() throws Exception {
                return _pool.execute(partitionContext, retryPolicy, callback);
            }
        });
    }

    @Override
    public <R> Collection<Future<R>> executeOnAll(RetryPolicy retry, ServiceCallback<S, R> callback) {
        return executeOn(ALL_END_POINTS, retry, callback);
    }

    @Override
    public <R> Collection<Future<R>> executeOn(ServiceEndPointPredicate predicate, final RetryPolicy retry,
                                               final ServiceCallback<S, R> callback) {
        Collection<Future<R>> futures = Lists.newArrayList();

        Iterable<ServiceEndPoint> endPoints = _pool.getAllEndPoints();
        if (Iterables.isEmpty(endPoints)) {
// Path: core/src/main/java/com/bazaarvoice/ostrich/PartitionContext.java
// public interface PartitionContext {
//     /**
//      * Gets the default piece of context. In many cases, there is only a single piece of relevant context, which this
//      * method should provide.
//      *
//      * @return The default context data.
//      */
//     Object get();
// 
//     /**
//      * Gets the context for the specified key.
//      * @param key The key for the desired context data.
//      * @return The context data.
//      */
//     Object get(String key);
// 
//     /**
//      * Gets a {@code Map} version of the context. The Map should be immutable.
//      * @return A {@code Map} with the same key/value pairs as this context.
//      */
//     Map<String, Object> asMap();
// }
// 
// Path: core/src/main/java/com/bazaarvoice/ostrich/exceptions/NoAvailableHostsException.java
// public class NoAvailableHostsException extends DiscoveryException {
//     private static final long serialVersionUID = 0;
// 
//     public NoAvailableHostsException() {
//         super();
//     }
// 
//     public NoAvailableHostsException(String message) {
//         super(message);
//     }
// 
//     public NoAvailableHostsException(String message, Throwable cause) {
//         super(message, cause);
//     }
// 
//     public NoAvailableHostsException(Throwable cause) {
//         super(cause);
//     }
// }


// Path: core/src/main/java/com/bazaarvoice/ostrich/pool/AsyncServicePool.java
import com.bazaarvoice.ostrich.PartitionContext;
import com.bazaarvoice.ostrich.RetryPolicy;
import com.bazaarvoice.ostrich.ServiceCallback;
import com.bazaarvoice.ostrich.ServiceEndPoint;
import com.bazaarvoice.ostrich.ServiceEndPointPredicate;
import com.bazaarvoice.ostrich.exceptions.MaxRetriesException;
import com.bazaarvoice.ostrich.exceptions.NoAvailableHostsException;
import com.bazaarvoice.ostrich.metrics.Metrics;
import com.codahale.metrics.Histogram;
import com.codahale.metrics.Meter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import com.google.common.base.Ticker;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import static com.google.common.base.Preconditions.checkNotNull;

            @Override
            public R call() throws Exception {
                return _pool.execute(retryPolicy, callback);
            }
        });
    }

    @Override
    public <R> Future<R> execute(final PartitionContext partitionContext, final RetryPolicy retryPolicy,
                                 final ServiceCallback<S, R> callback) {
        return _executor.submit(new Callable<R>() {
            @Override
            public R call() throws Exception {
                return _pool.execute(partitionContext, retryPolicy, callback);
            }
        });
    }

    @Override
    public <R> Collection<Future<R>> executeOnAll(RetryPolicy retry, ServiceCallback<S, R> callback) {
        return executeOn(ALL_END_POINTS, retry, callback);
    }

    @Override
    public <R> Collection<Future<R>> executeOn(ServiceEndPointPredicate predicate, final RetryPolicy retry,
                                               final ServiceCallback<S, R> callback) {
        Collection<Future<R>> futures = Lists.newArrayList();

        Iterable<ServiceEndPoint> endPoints = _pool.getAllEndPoints();
        if (Iterables.isEmpty(endPoints)) {
            throw new NoAvailableHostsException(String.format("No hosts discovered for service %s", _pool.getServiceName()));