// 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/PartitionContextBuilder.java
// public final class PartitionContextBuilder {
//     private static final PartitionContext EMPTY = new Context(ImmutableMap.<String, Object>of());
// 
//     private final ImmutableMap.Builder<String, Object> _map = ImmutableMap.builder();
// 
//     public static PartitionContext empty() {
//         return EMPTY;
//     }
// 
//     public static PartitionContext of(Object obj) {
//         return new Context(ImmutableMap.of("", obj));
//     }
// 
//     public static PartitionContext of(String key, Object value) {
//         return new Context(ImmutableMap.of(key, value));
//     }
// 
//     public static PartitionContext of(String key1, Object value1, String key2, Object value2) {
//         return new Context(ImmutableMap.of(key1, value1, key2, value2));
//     }
// 
//     /**
//      * Adds the specified key and value to the partition context.  Null keys or values and duplicate keys are not
//      * allowed.
//      *
//      * @return this
//      */
//     public PartitionContextBuilder put(String key, Object value) {
//         _map.put(key, value);
//         return this;
//     }
// 
//     /**
//      * Adds the specified keys and values to the partition context.  Null keys or values and duplicate keys are not
//      * allowed.
//      *
//      * @return this
//      */
//     public PartitionContextBuilder putAll(Map<String, ?> map) {
//         _map.putAll(map);
//         return this;
//     }
// 
//     /**
//      * Returns a newly-create immutable {@code PartitionContext}.
//      */
//     public PartitionContext build() {
//         return new Context(_map.build());
//     }
// 
//     private static class Context implements PartitionContext {
//         private final ImmutableMap<String, Object> _map;
// 
//         private Context(ImmutableMap<String, Object> map) {
//             _map = checkNotNull(map);
//         }
// 
//         @Override
//         public Object get() {
//             return _map.get("");
//         }
// 
//         @Override
//         public Object get(String key) {
//             return _map.get(key);
//         }
// 
//         @Override
//         public Map<String, Object> asMap() {
//             return _map;
//         }
// 
//         @Override
//         public boolean equals(Object o) {
//             return this == o || (o instanceof Context && _map.equals(((Context) o)._map));
//         }
// 
//         @Override
//         public int hashCode() {
//             return 95261 + _map.hashCode();
//         }
//     }
// }


import com.bazaarvoice.ostrich.PartitionContext;
import com.bazaarvoice.ostrich.PartitionContextBuilder;
import com.bazaarvoice.ostrich.partition.PartitionKey;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Map;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
            if (keyMappings == null) {
                continue;  // Not annotated
            }

            // Index by the ifcMethod because that's the method provided when a dynamic proxy method is invoked.
            builder.put(ifcMethod, keyMappings);
        }
        _keyMappings = builder.build();
    }

    @Override
    public PartitionContext forCall(Method method, Object... args) {
        String[] mappings = _keyMappings.get(method);
        if (mappings == null) {
            return PartitionContextBuilder.empty();
        }

        PartitionContextBuilder builder = new PartitionContextBuilder();
        for (int i = 0; i < mappings.length; i++) {
            if (mappings[i] != null && args[i] != null) {
                builder.put(mappings[i], args[i]);
            }
        }
        return builder.build();
    }

    /**
     * Returns an array indexed by argument index with the value of the @PartitionKey annotation for each argument,
     * or null if no arguments are annotated with @PartitionKey.
     */
// 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/PartitionContextBuilder.java
// public final class PartitionContextBuilder {
//     private static final PartitionContext EMPTY = new Context(ImmutableMap.<String, Object>of());
// 
//     private final ImmutableMap.Builder<String, Object> _map = ImmutableMap.builder();
// 
//     public static PartitionContext empty() {
//         return EMPTY;
//     }
// 
//     public static PartitionContext of(Object obj) {
//         return new Context(ImmutableMap.of("", obj));
//     }
// 
//     public static PartitionContext of(String key, Object value) {
//         return new Context(ImmutableMap.of(key, value));
//     }
// 
//     public static PartitionContext of(String key1, Object value1, String key2, Object value2) {
//         return new Context(ImmutableMap.of(key1, value1, key2, value2));
//     }
// 
//     /**
//      * Adds the specified key and value to the partition context.  Null keys or values and duplicate keys are not
//      * allowed.
//      *
//      * @return this
//      */
//     public PartitionContextBuilder put(String key, Object value) {
//         _map.put(key, value);
//         return this;
//     }
// 
//     /**
//      * Adds the specified keys and values to the partition context.  Null keys or values and duplicate keys are not
//      * allowed.
//      *
//      * @return this
//      */
//     public PartitionContextBuilder putAll(Map<String, ?> map) {
//         _map.putAll(map);
//         return this;
//     }
// 
//     /**
//      * Returns a newly-create immutable {@code PartitionContext}.
//      */
//     public PartitionContext build() {
//         return new Context(_map.build());
//     }
// 
//     private static class Context implements PartitionContext {
//         private final ImmutableMap<String, Object> _map;
// 
//         private Context(ImmutableMap<String, Object> map) {
//             _map = checkNotNull(map);
//         }
// 
//         @Override
//         public Object get() {
//             return _map.get("");
//         }
// 
//         @Override
//         public Object get(String key) {
//             return _map.get(key);
//         }
// 
//         @Override
//         public Map<String, Object> asMap() {
//             return _map;
//         }
// 
//         @Override
//         public boolean equals(Object o) {
//             return this == o || (o instanceof Context && _map.equals(((Context) o)._map));
//         }
// 
//         @Override
//         public int hashCode() {
//             return 95261 + _map.hashCode();
//         }
//     }
// }


// Path: core/src/main/java/com/bazaarvoice/ostrich/pool/AnnotationPartitionContextSupplier.java
import com.bazaarvoice.ostrich.PartitionContext;
import com.bazaarvoice.ostrich.PartitionContextBuilder;
import com.bazaarvoice.ostrich.partition.PartitionKey;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Map;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

            if (keyMappings == null) {
                continue;  // Not annotated
            }

            // Index by the ifcMethod because that's the method provided when a dynamic proxy method is invoked.
            builder.put(ifcMethod, keyMappings);
        }
        _keyMappings = builder.build();
    }

    @Override
    public PartitionContext forCall(Method method, Object... args) {
        String[] mappings = _keyMappings.get(method);
        if (mappings == null) {
            return PartitionContextBuilder.empty();
        }

        PartitionContextBuilder builder = new PartitionContextBuilder();
        for (int i = 0; i < mappings.length; i++) {
            if (mappings[i] != null && args[i] != null) {
                builder.put(mappings[i], args[i]);
            }
        }
        return builder.build();
    }

    /**
     * Returns an array indexed by argument index with the value of the @PartitionKey annotation for each argument,
     * or null if no arguments are annotated with @PartitionKey.
     */
    private String[] collectPartitionKeyAnnotations(Method method) {