// 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();
// }


import com.bazaarvoice.ostrich.PartitionContext;
import com.bazaarvoice.ostrich.RetryPolicy;
import com.bazaarvoice.ostrich.ServiceCallback;
import com.bazaarvoice.ostrich.ServicePool;
import com.bazaarvoice.ostrich.exceptions.ServiceException;
import com.google.common.base.Throwables;
import com.google.common.reflect.AbstractInvocationHandler;
import java.io.Closeable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
                serviceType, retryPolicy, pool, partitionContextSupplier, shutdownPoolOnClose);
        return serviceType.cast(Proxy.newProxyInstance(loader, interfaces, proxy));
    }

    ServicePoolProxy(Class<S> serviceType, RetryPolicy retryPolicy, ServicePool<S> servicePool,
                     PartitionContextSupplier partitionContextSupplier, boolean shutdownPoolOnClose) {
        checkState(serviceType.isInterface(), "Proxy functionality is only available for interface service types.");

        _serviceType = checkNotNull(serviceType);
        _retryPolicy = checkNotNull(retryPolicy);
        _servicePool = checkNotNull(servicePool);
        _partitionContextSupplier = checkNotNull(partitionContextSupplier);
        _shutdownPoolOnClose = shutdownPoolOnClose;
    }

    /**
     * @return The service pool used by this proxy to execute service methods.
     */
    com.bazaarvoice.ostrich.ServicePool<S> getServicePool() {
        return _servicePool;
    }

    @Override
    protected Object handleInvocation(Object proxy, final Method method, final Object[] args) throws Throwable {
        // Special case for close() allows closing the entire pool by calling close() on the proxy.
        if (_shutdownPoolOnClose && args.length == 0 && method.getName().equals("close")) {
            _servicePool.close();
            return null;
        }

// 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/pool/ServicePoolProxy.java
import com.bazaarvoice.ostrich.PartitionContext;
import com.bazaarvoice.ostrich.RetryPolicy;
import com.bazaarvoice.ostrich.ServiceCallback;
import com.bazaarvoice.ostrich.ServicePool;
import com.bazaarvoice.ostrich.exceptions.ServiceException;
import com.google.common.base.Throwables;
import com.google.common.reflect.AbstractInvocationHandler;
import java.io.Closeable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

                serviceType, retryPolicy, pool, partitionContextSupplier, shutdownPoolOnClose);
        return serviceType.cast(Proxy.newProxyInstance(loader, interfaces, proxy));
    }

    ServicePoolProxy(Class<S> serviceType, RetryPolicy retryPolicy, ServicePool<S> servicePool,
                     PartitionContextSupplier partitionContextSupplier, boolean shutdownPoolOnClose) {
        checkState(serviceType.isInterface(), "Proxy functionality is only available for interface service types.");

        _serviceType = checkNotNull(serviceType);
        _retryPolicy = checkNotNull(retryPolicy);
        _servicePool = checkNotNull(servicePool);
        _partitionContextSupplier = checkNotNull(partitionContextSupplier);
        _shutdownPoolOnClose = shutdownPoolOnClose;
    }

    /**
     * @return The service pool used by this proxy to execute service methods.
     */
    com.bazaarvoice.ostrich.ServicePool<S> getServicePool() {
        return _servicePool;
    }

    @Override
    protected Object handleInvocation(Object proxy, final Method method, final Object[] args) throws Throwable {
        // Special case for close() allows closing the entire pool by calling close() on the proxy.
        if (_shutdownPoolOnClose && args.length == 0 && method.getName().equals("close")) {
            _servicePool.close();
            return null;
        }

        PartitionContext partitionContext = _partitionContextSupplier.forCall(method, args);