http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/ExceptionalClosure.java
----------------------------------------------------------------------
diff --git 
a/commons/src/main/java/com/twitter/common/base/ExceptionalClosure.java 
b/commons/src/main/java/com/twitter/common/base/ExceptionalClosure.java
new file mode 100644
index 0000000..99c6993
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/base/ExceptionalClosure.java
@@ -0,0 +1,38 @@
+// 
=================================================================================================
+// Copyright 2011 Twitter, Inc.
+// 
-------------------------------------------------------------------------------------------------
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this work except in compliance with the License.
+// You may obtain a copy of the License in the LICENSE file, or at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
=================================================================================================
+
+package com.twitter.common.base;
+
+/**
+ * An interface that captures a unit of work against an item.
+ *
+ * @param <T> The closure type.
+ * @param <E> The exception type thrown by the closure.
+ *
+ * @author John Sirois
+ */
+public interface ExceptionalClosure<T, E extends Exception> {
+
+  /**
+   * Performs a unit of work on item, possibly throwing {@code E} in the 
process.
+   *
+   * <p>TODO(John Sirois): consider supporting @Nullable
+   *
+   * @param item the item to perform work against
+   * @throws E if there was a problem performing the work
+   */
+  void execute(T item) throws E;
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/ExceptionalCommand.java
----------------------------------------------------------------------
diff --git 
a/commons/src/main/java/com/twitter/common/base/ExceptionalCommand.java 
b/commons/src/main/java/com/twitter/common/base/ExceptionalCommand.java
new file mode 100644
index 0000000..7825199
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/base/ExceptionalCommand.java
@@ -0,0 +1,34 @@
+// 
=================================================================================================
+// Copyright 2011 Twitter, Inc.
+// 
-------------------------------------------------------------------------------------------------
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this work except in compliance with the License.
+// You may obtain a copy of the License in the LICENSE file, or at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
=================================================================================================
+
+package com.twitter.common.base;
+
+/**
+ * An interface that captures a unit of work.
+ *
+ * @param <E> The type of exception that the command throws.
+ *
+ * @author John Sirois
+ */
+public interface ExceptionalCommand<E extends Exception> {
+
+  /**
+   * Performs a unit of work, possibly throwing {@code E} in the process.
+   *
+   * @throws E if there was a problem performing the work
+   */
+  void execute() throws E;
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/ExceptionalFunction.java
----------------------------------------------------------------------
diff --git 
a/commons/src/main/java/com/twitter/common/base/ExceptionalFunction.java 
b/commons/src/main/java/com/twitter/common/base/ExceptionalFunction.java
new file mode 100644
index 0000000..9f9d6b0
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/base/ExceptionalFunction.java
@@ -0,0 +1,40 @@
+// 
=================================================================================================
+// Copyright 2011 Twitter, Inc.
+// 
-------------------------------------------------------------------------------------------------
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this work except in compliance with the License.
+// You may obtain a copy of the License in the LICENSE file, or at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
=================================================================================================
+
+package com.twitter.common.base;
+
+/**
+ * An interface that captures a unit of work against an item.
+ *
+ * @param <S> The argument type for the function.
+ * @param <T> The return type for the function.
+ * @param <E> The exception type that the function throws.
+ *
+ * @author John Sirois
+ */
+public interface ExceptionalFunction<S, T, E extends Exception> {
+
+  /**
+   * Performs a unit of work on item, possibly throwing {@code E} in the 
process.
+   *
+   * <p>TODO(John Sirois): consider supporting @Nullable
+   *
+   * @param item The item to perform work against.
+   * @return The result of the computation.
+   * @throws E if there was a problem performing the work.
+   */
+  T apply(S item) throws E;
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/ExceptionalFunctions.java
----------------------------------------------------------------------
diff --git 
a/commons/src/main/java/com/twitter/common/base/ExceptionalFunctions.java 
b/commons/src/main/java/com/twitter/common/base/ExceptionalFunctions.java
new file mode 100644
index 0000000..9adcc4d
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/base/ExceptionalFunctions.java
@@ -0,0 +1,156 @@
+// 
=================================================================================================
+// Copyright 2011 Twitter, Inc.
+// 
-------------------------------------------------------------------------------------------------
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this work except in compliance with the License.
+// You may obtain a copy of the License in the LICENSE file, or at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
=================================================================================================
+
+package com.twitter.common.base;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Utility functions for working with exceptional functions.
+ *
+ * @author John Sirois
+ */
+public final class ExceptionalFunctions {
+
+  private ExceptionalFunctions() {
+    // utility
+  }
+
+  /**
+   * Returns an {@link ExceptionalSupplier}/{@link 
java.util.concurrent.Callable} object that will
+   * return the result of {@code function} applied to {@code argument}.  
Evaluation is lazy and
+   * un-memoized.
+   */
+  public static <S, T, E extends Exception> CallableExceptionalSupplier<T, E> 
curry(
+      final ExceptionalFunction<S, T, E> function, final S argument) {
+
+    return new CallableExceptionalSupplier<T, E>() {
+      @Override
+      public T get() throws E {
+        return function.apply(argument);
+      }
+    };
+  }
+
+  /**
+   * Returns an ExceptionalFunction that is a composition of multiple 
ExceptionalFunctions.
+   */
+  public static <T, E extends Exception> ExceptionalFunction<T, T, E> compose(
+      final Iterable<ExceptionalFunction<T, T, E>> functions) {
+    return new ExceptionalFunction<T, T, E>() {
+      @Override
+      public T apply(T input) throws E {
+        T result = input;
+        for (ExceptionalFunction<T, T, E> f : functions) {
+          result = f.apply(result);
+        }
+        return result;
+      }
+    };
+  }
+
+  /**
+   * Returns a List of ExceptionalFunctions from variable number of 
ExceptionalFunctions.
+   */
+  public static <T, E extends Exception> ExceptionalFunction<T, T, E> compose(
+      ExceptionalFunction<T, T, E> function, ExceptionalFunction<T, T, E>... 
functions) {
+    return compose(ImmutableList.<ExceptionalFunction<T, T, E>>builder()
+        .add(function)
+        .add(functions)
+        .build());
+  }
+
+  /**
+   * Returns a new ExceptionalFunction which composes two ExceptionalFunctions 
of compatible types.
+   *
+   * @param second function to apply to result of first.
+   * @param first function to apply to input item.
+   * @param <A> input type of first.
+   * @param <B> input type of second.
+   * @param <C> output type of second.
+   * @param <E> exception type.
+   * @return new composed ExceptionalFunction.
+   */
+  public static <A, B, C, E extends Exception> ExceptionalFunction<A, C, E> 
compose(
+      final ExceptionalFunction<B, C, ? extends E> second,
+      final ExceptionalFunction<A, ? extends B, ? extends E> first) {
+    return new ExceptionalFunction<A, C, E>() {
+      @Override
+      public C apply(A item) throws E {
+        return second.apply(first.apply(item));
+      }
+    };
+  }
+
+  /**
+   * Builds an ExceptionalFunction from {@link 
com.google.common.base.Function}.
+   *
+   * @param function guava Function.
+   * @param <S> input type.
+   * @param <T> output type.
+   * @param <E> exception type.
+   * @return new ExceptionalFunction.
+   */
+  public static <S, T, E extends Exception> ExceptionalFunction<S, T, E> 
forFunction(
+      final com.google.common.base.Function<S, T> function) {
+    return new ExceptionalFunction<S, T, E>() {
+      @Override
+      public T apply(S item) {
+        return function.apply(item);
+      }
+    };
+  }
+
+  /**
+   * Builds an ExceptionalFunction from a return value. The returned 
ExceptionalFunction will always
+   * return the given value.
+   *
+   * @param value value to return.
+   * @param <S> input type.
+   * @param <T> output type.
+   * @param <E> exception type.
+   * @return new ExceptionalFunction.
+   */
+  public static <S, T, E extends Exception> ExceptionalFunction<S, T, E> 
constant(
+      final T value) {
+    return new ExceptionalFunction<S, T, E>() {
+      @Override
+      public T apply(S item) throws E {
+        return value;
+      }
+    };
+  }
+
+  /**
+   * Builds an ExceptionalFunction from an Exception. The returned 
ExceptionalFunction will always
+   * throw the given Exception.
+   *
+   * @param exception exception to throw.
+   * @param <S> input type.
+   * @param <T> output type.
+   * @param <E> exception type.
+   * @return new ExceptionalFunction.
+   */
+  public static <S, T, E extends Exception> ExceptionalFunction<S, T, E> 
forException(
+      final E exception) {
+    return new ExceptionalFunction<S, T, E>() {
+      @Override
+      public T apply(S item) throws E {
+        throw exception;
+      }
+    };
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/ExceptionalSupplier.java
----------------------------------------------------------------------
diff --git 
a/commons/src/main/java/com/twitter/common/base/ExceptionalSupplier.java 
b/commons/src/main/java/com/twitter/common/base/ExceptionalSupplier.java
new file mode 100644
index 0000000..6f8e877
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/base/ExceptionalSupplier.java
@@ -0,0 +1,36 @@
+// 
=================================================================================================
+// Copyright 2011 Twitter, Inc.
+// 
-------------------------------------------------------------------------------------------------
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this work except in compliance with the License.
+// You may obtain a copy of the License in the LICENSE file, or at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
=================================================================================================
+
+package com.twitter.common.base;
+
+/**
+ * An interface that captures a source of data.
+ *
+ * @param <T> The supplied value type.
+ * @param <E> The type of exception that the supplier throws.
+ *
+ * @author John Sirois
+ */
+public interface ExceptionalSupplier<T, E extends Exception> {
+
+  /**
+   * Supplies an item, possibly throwing {@code E} in the process of obtaining 
the item.
+   *
+   * @return the result of the computation
+   * @throws E if there was a problem performing the work
+   */
+  T get() throws E;
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/Function.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/base/Function.java 
b/commons/src/main/java/com/twitter/common/base/Function.java
new file mode 100644
index 0000000..1eaa2cc
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/base/Function.java
@@ -0,0 +1,32 @@
+// 
=================================================================================================
+// Copyright 2011 Twitter, Inc.
+// 
-------------------------------------------------------------------------------------------------
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this work except in compliance with the License.
+// You may obtain a copy of the License in the LICENSE file, or at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
=================================================================================================
+
+package com.twitter.common.base;
+
+/**
+ * A convenience typedef that also ties into google's {@code Function}.
+ *
+ * @param <S> The argument type for the function.
+ * @param <T> The return type for the function.
+ *
+ * @author John Sirois
+ */
+public interface Function<S, T>
+    extends ExceptionalFunction<S, T, RuntimeException>, 
com.google.common.base.Function<S, T> {
+
+  @Override
+  T apply(S item);
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/MorePreconditions.java
----------------------------------------------------------------------
diff --git 
a/commons/src/main/java/com/twitter/common/base/MorePreconditions.java 
b/commons/src/main/java/com/twitter/common/base/MorePreconditions.java
new file mode 100644
index 0000000..9da8d82
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/base/MorePreconditions.java
@@ -0,0 +1,147 @@
+// 
=================================================================================================
+// Copyright 2011 Twitter, Inc.
+// 
-------------------------------------------------------------------------------------------------
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this work except in compliance with the License.
+// You may obtain a copy of the License in the LICENSE file, or at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
=================================================================================================
+
+package com.twitter.common.base;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * A utility helpful in concisely checking preconditions on arguments.  This 
utility is a complement
+ * to {@link com.google.common.base.Preconditions}.
+ *
+ * @author John Sirois
+ */
+public final class MorePreconditions {
+
+  private static final String ARG_NOT_BLANK_MSG = "Argument cannot be blank";
+
+  private MorePreconditions() {
+    // utility
+  }
+
+  /**
+   * Checks that a string is both non-null and non-empty.
+   *
+   * @see #checkNotBlank(String, String, Object...)
+   */
+  public static String checkNotBlank(String argument) {
+    return checkNotBlank(argument, ARG_NOT_BLANK_MSG);
+  }
+
+  /**
+   * Checks that a string is both non-null and non-empty.
+   *
+   * @param argument the argument to validate
+   * @param message the message template for validation exception messages 
where %s serves as the
+   *     sole argument placeholder
+   * @param args any arguments needed by the message template
+   * @return the argument if it is valid
+   * @throws NullPointerException if the argument is null
+   * @throws IllegalArgumentException if the argument is the empty string or a 
pure whitespace
+   *    string
+   */
+  public static String checkNotBlank(String argument, String message, 
Object... args) {
+    Preconditions.checkNotNull(argument, message, args);
+    Preconditions.checkArgument(!StringUtils.isBlank(argument), message, args);
+    return argument;
+  }
+
+  /**
+   * Checks that an Iterable is both non-null and non-empty.  This method does 
not check individual
+   * elements in the Iterable.
+   *
+   * @see #checkNotBlank(Iterable, String, Object...)
+   */
+  public static <S, T extends Iterable<S>> T checkNotBlank(T argument) {
+    return checkNotBlank(argument, ARG_NOT_BLANK_MSG);
+  }
+
+  /**
+   * Checks that an Iterable is both non-null and non-empty.  This method does 
not check individual
+   * elements in the Iterable, it just checks that the Iterable has at least 
one element.
+   *
+   * @param argument the argument to validate
+   * @param message the message template for validation exception messages 
where %s serves as the
+   *     sole argument placeholder
+   * @param args any arguments needed by the message template
+   * @return the argument if it is valid
+   * @throws NullPointerException if the argument is null
+   * @throws IllegalArgumentException if the argument has no iterable elements
+   */
+  public static <S, T extends Iterable<S>> T checkNotBlank(T argument, String 
message,
+      Object... args) {
+    Preconditions.checkNotNull(argument, message, args);
+    Preconditions.checkArgument(!Iterables.isEmpty(argument), message, args);
+    return argument;
+  }
+
+  /**
+   * Checks that a double falls within a specified range, inclusive
+   *
+   * @param argument argument to validate.
+   * @param minimum minimum possible valid value for the argument.
+   * @param maximum maximum possible valid value for the argument.
+   * @param message the message template for validation exception messages 
where %s serves as the
+   *                sole argument placeholder.
+   * @return the argument if it is valid.
+   * @throws IllegalArgumentException if the argument falls outside of the 
specified range.
+   */
+  public static double checkArgumentRange(double argument, double minimum, 
double maximum,
+      String message) {
+    Preconditions.checkArgument(minimum <= argument, message, argument);
+    Preconditions.checkArgument(argument <= maximum, message, argument);
+    return argument;
+  }
+
+  /**
+   * Checks that an int falls within a specified range, inclusive
+   *
+   * @param argument argument to validate.
+   * @param minimum minimum possible valid value for the argument.
+   * @param maximum maximum possible valid value for the argument.
+   * @param message the message template for validation exception messages 
where %s serves as the
+   *                sole argument placeholder.
+   * @return the argument if it is valid.
+   * @throws IllegalArgumentException if the argument falls outside of the 
specified range.
+   */
+  public static int checkArgumentRange(int argument, int minimum, int maximum,
+      String message) {
+    Preconditions.checkArgument(minimum <= argument, message, argument);
+    Preconditions.checkArgument(argument <= maximum, message, argument);
+    return argument;
+  }
+
+  /**
+   * Checks that at least one of the specified arguments is true.
+   *
+   * @param message the message for validation exception messages.
+   * @param arguments one or more arguments to check.
+   * @return true if at least one of the arguments is true.
+   * @throws IllegalArgumentException if none of the arguments are true.
+   */
+  public static boolean checkArguments(String message,
+      Boolean... arguments) {
+    for (Boolean argument : arguments) {
+      if (argument) {
+        return true;
+      }
+    }
+    throw new IllegalArgumentException(message);
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/MoreSuppliers.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/base/MoreSuppliers.java 
b/commons/src/main/java/com/twitter/common/base/MoreSuppliers.java
new file mode 100644
index 0000000..2b77b72
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/base/MoreSuppliers.java
@@ -0,0 +1,106 @@
+// 
=================================================================================================
+// Copyright 2011 Twitter, Inc.
+// 
-------------------------------------------------------------------------------------------------
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this work except in compliance with the License.
+// You may obtain a copy of the License in the LICENSE file, or at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
=================================================================================================
+
+package com.twitter.common.base;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
+
+import javax.annotation.Nullable;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * Utility methods for working with Suppliers.
+ *
+ * @author John Sirois
+ */
+public final class MoreSuppliers {
+
+  private MoreSuppliers() {
+    // utility
+  }
+
+  /**
+   * Creates a Supplier that uses the no-argument constructor of {@code type} 
to supply new
+   * instances.
+   *
+   * @param type the type of object this supplier creates
+   * @param <T> the type of object this supplier creates
+   * @return a Supplier that created a new obeject of type T on each call to 
{@link Supplier#get()}
+   * @throws IllegalArgumentException if the given {@code type} does not have 
a no-arg constructor
+   */
+  public static <T> Supplier<T> of(final Class<? extends T> type) {
+    Preconditions.checkNotNull(type);
+
+    try {
+      final Constructor<? extends T> constructor = getNoArgConstructor(type);
+      return new Supplier<T>() {
+        @Override public T get() {
+          try {
+            return constructor.newInstance();
+          } catch (InstantiationException e) {
+            throw instantiationFailed(e, type);
+          } catch (IllegalAccessException e) {
+            throw instantiationFailed(e, type);
+          } catch (InvocationTargetException e) {
+            throw instantiationFailed(e, type);
+          }
+        }
+      };
+    } catch (NoSuchMethodException e) {
+      throw new IllegalArgumentException("No accessible no-arg constructor for 
" + type, e);
+    }
+  }
+
+  private static RuntimeException instantiationFailed(Exception cause, Object 
type) {
+    return new RuntimeException("Could not create a new instance of type: " + 
type, cause);
+  }
+
+  private static <T> Constructor<T> getNoArgConstructor(Class<T> type)
+    throws NoSuchMethodException {
+
+    try {
+      Constructor<T> constructor = type.getConstructor();
+      if (!MoreSuppliers.class.getPackage().equals(type.getPackage())
+          && !Modifier.isPublic(type.getModifiers())) {
+        // Handle a public no-args constructor in a non-public class
+        constructor.setAccessible(true);
+      }
+      return constructor;
+    } catch (NoSuchMethodException e) {
+      Constructor<T> declaredConstructor = type.getDeclaredConstructor();
+      declaredConstructor.setAccessible(true);
+      return declaredConstructor;
+    }
+  }
+
+  /**
+   * Returns an {@link ExceptionalSupplier} that always supplies {@code item} 
without error.
+   *
+   * @param item The item to supply.
+   * @param <T> The type of item being supplied.
+   * @return A supplier that will always supply {@code item}.
+   */
+  public static <T> Supplier<T> ofInstance(@Nullable final T item) {
+    return new Supplier<T>() {
+      @Override public T get() {
+        return item;
+      }
+    };
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/Supplier.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/base/Supplier.java 
b/commons/src/main/java/com/twitter/common/base/Supplier.java
new file mode 100644
index 0000000..4270b16
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/base/Supplier.java
@@ -0,0 +1,31 @@
+// 
=================================================================================================
+// Copyright 2011 Twitter, Inc.
+// 
-------------------------------------------------------------------------------------------------
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this work except in compliance with the License.
+// You may obtain a copy of the License in the LICENSE file, or at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
=================================================================================================
+
+package com.twitter.common.base;
+
+/**
+ * A convenience typedef that also ties into google's {@code Supplier}.
+ *
+ * @param <T> The supplied type.
+ *
+ * @author John Sirois
+ */
+public interface Supplier<T>
+    extends ExceptionalSupplier<T, RuntimeException>, 
com.google.common.base.Supplier<T> {
+
+  @Override
+  T get();
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/SupplierE.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/base/SupplierE.java 
b/commons/src/main/java/com/twitter/common/base/SupplierE.java
new file mode 100644
index 0000000..3b15cc3
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/base/SupplierE.java
@@ -0,0 +1,28 @@
+// 
=================================================================================================
+// Copyright 2011 Twitter, Inc.
+// 
-------------------------------------------------------------------------------------------------
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this work except in compliance with the License.
+// You may obtain a copy of the License in the LICENSE file, or at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
=================================================================================================
+
+package com.twitter.common.base;
+
+/**
+ * A convenience typedef for suppliers that throw multiple exception types.
+ *
+ * @param <T> The supplied type.
+ *
+ * @author John Sirois
+ */
+public interface SupplierE<T> extends ExceptionalSupplier<T, Exception> {
+  // typedef
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/collections/Bits.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/collections/Bits.java 
b/commons/src/main/java/com/twitter/common/collections/Bits.java
new file mode 100644
index 0000000..5b4be70
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/collections/Bits.java
@@ -0,0 +1,119 @@
+// 
=================================================================================================
+// Copyright 2011 Twitter, Inc.
+// 
-------------------------------------------------------------------------------------------------
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this work except in compliance with the License.
+// You may obtain a copy of the License in the LICENSE file, or at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
=================================================================================================
+
+package com.twitter.common.collections;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * Convenience class for doing bit-level operations on ints and longs.
+ *
+ * @author William Farner
+ */
+public final class Bits {
+
+  private static final int LSB = 0;
+  private static final int INT_MSB = 31;
+  private static final int LONG_MSB = 63;
+
+  private Bits() {
+    // Utility.
+  }
+
+  /**
+   * Tests whether a bit is set in an int value.
+   *
+   * @param value The bit field to test.
+   * @param bit The index of the bit to test, where bit 0 is the LSB.
+   * @return {@code true} if the bit is set, {@code false} otherwise.
+   */
+  public static boolean isBitSet(int value, int bit) {
+    Preconditions.checkState(bit >= LSB);
+    Preconditions.checkState(bit <= INT_MSB);
+    int mask = 1 << bit;
+    return (value & mask) != 0;
+  }
+
+  /**
+   * Tests whether a bit is set in a long value.
+   *
+   * @param value The bit field to test.
+   * @param bit The index of the bit to test, where bit 0 is the LSB.
+   * @return {@code true} if the bit is set, {@code false} otherwise.
+   */
+  public static boolean isBitSet(long value, int bit) {
+    Preconditions.checkState(bit >= LSB);
+    Preconditions.checkState(bit <= LONG_MSB);
+    long mask = 1L << bit;
+    return (value & mask) != 0;
+  }
+
+  /**
+   * Sets a bit in an int value.
+   *
+   * @param value The bit field to modify.
+   * @param bit The index of the bit to set, where bit 0 is the LSB.
+   * @return The original value, with the indexed bit set.
+   */
+  public static int setBit(int value, int bit) {
+    Preconditions.checkState(bit >= LSB);
+    Preconditions.checkState(bit <= INT_MSB);
+    int mask = 1 << bit;
+    return value | mask;
+  }
+
+  /**
+   * Sets a bit in a long value.
+   *
+   * @param value The bit field to modify.
+   * @param bit The index of the bit to set, where bit 0 is the LSB.
+   * @return The original value, with the indexed bit set.
+   */
+  public static long setBit(long value, int bit) {
+    Preconditions.checkState(bit >= LSB);
+    Preconditions.checkState(bit <= LONG_MSB);
+    long mask = 1L << bit;
+    return value | mask;
+  }
+
+  /**
+   * Clears a bit in an int value.
+   *
+   * @param value The bit field to modify.
+   * @param bit The index of the bit to clear, where bit 0 is the LSB.
+   * @return The original value, with the indexed bit clear.
+   */
+  public static int clearBit(int value, int bit) {
+    Preconditions.checkState(bit >= LSB);
+    Preconditions.checkState(bit <= INT_MSB);
+    int mask = ~setBit(0, bit);
+    return value & mask;
+  }
+
+  /**
+   * Clears a bit in a long value.
+   *
+   * @param value The bit field to modify.
+   * @param bit The index of the bit to clear, where bit 0 is the LSB.
+   * @return The original value, with the indexed bit clear.
+   */
+  public static long clearBit(long value, int bit) {
+    Preconditions.checkState(bit >= LSB);
+    Preconditions.checkState(bit <= LONG_MSB);
+    long mask = ~setBit(0L, bit);
+    return value & mask;
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/collections/BoundedQueue.java
----------------------------------------------------------------------
diff --git 
a/commons/src/main/java/com/twitter/common/collections/BoundedQueue.java 
b/commons/src/main/java/com/twitter/common/collections/BoundedQueue.java
new file mode 100644
index 0000000..58c5fad
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/collections/BoundedQueue.java
@@ -0,0 +1,79 @@
+// 
=================================================================================================
+// Copyright 2011 Twitter, Inc.
+// 
-------------------------------------------------------------------------------------------------
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this work except in compliance with the License.
+// You may obtain a copy of the License in the LICENSE file, or at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
=================================================================================================
+
+package com.twitter.common.collections;
+
+import java.util.Iterator;
+import java.util.concurrent.LinkedBlockingDeque;
+
+/**
+ * A limited implementation of a bounded queue.  Values can be added and 
iterated over, and will
+ * automatically expire when the queue exceeds capacity.
+ *
+ * @param <T> The type that this queue contains.
+ *
+ * @author William Farner
+*/
+public class BoundedQueue<T> implements Iterable<T> {
+  private final LinkedBlockingDeque<T> values;
+
+  /**
+   * Creates a new bounded queue.
+   *
+   * @param limit Maximum number of items that can be in the queue at any time.
+   */
+  public BoundedQueue(int limit) {
+    values = new LinkedBlockingDeque<T>(limit);
+  }
+
+  /**
+   * Adds a value to head of the queue, evicting the oldest item if the queue 
is at capacity.
+   *
+   * @param value Value to add.
+   */
+  public synchronized void add(T value) {
+    if (values.remainingCapacity() == 0) {
+      values.removeFirst();
+    }
+    values.addLast(value);
+  }
+
+  /**
+   * Removes all values from the queue.
+   */
+  public synchronized void clear() {
+    values.clear();
+  }
+
+  /**
+   * Returns the size of the queue.
+   *
+   * @return The current queue length.
+   */
+  public synchronized int size() {
+    return values.size();
+  }
+
+  @Override
+  public synchronized Iterator<T> iterator() {
+    return values.iterator();
+  }
+
+  @Override
+  public synchronized String toString() {
+    return values.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/collections/Iterables2.java
----------------------------------------------------------------------
diff --git 
a/commons/src/main/java/com/twitter/common/collections/Iterables2.java 
b/commons/src/main/java/com/twitter/common/collections/Iterables2.java
new file mode 100644
index 0000000..1086558
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/collections/Iterables2.java
@@ -0,0 +1,151 @@
+// 
=================================================================================================
+// Copyright 2011 Twitter, Inc.
+// 
-------------------------------------------------------------------------------------------------
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this work except in compliance with the License.
+// You may obtain a copy of the License in the LICENSE file, or at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
=================================================================================================
+
+package com.twitter.common.collections;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import com.google.common.base.Function;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+/**
+ * Utility functions for dealing with iterables.
+ *
+ * @author William Farner
+ */
+public final class Iterables2 {
+
+  private Iterables2() {
+    // Utility class.
+  }
+
+  /**
+   * An iterator that zips multiple iterables into a single list iterator, 
filling missing values
+   * with a provided default.
+   *
+   * @param <T> The value type for the iterator.
+   */
+  private static class ZippingIterator<T> implements Iterator<List<T>> {
+
+    private final Iterable<Iterable<T>> iterables;
+    private final T defaultValue;
+
+    private List<Iterator<T>> iterators = null;
+    private final LoadingCache<Iterator<T>, Boolean> overflowing = 
CacheBuilder.newBuilder().build(
+        new CacheLoader<Iterator<T>, Boolean>() {
+          @Override public Boolean load(Iterator<T> iterator) {
+            return false;
+          }
+        });
+
+    ZippingIterator(Iterable<Iterable<T>> iterables, T defaultValue) {
+      this.iterables = iterables;
+      this.defaultValue = defaultValue;
+    }
+
+    private void init() {
+      if (iterators == null) {
+        // Iterables -> Iterators.
+        iterators = ImmutableList.copyOf(Iterables.transform(iterables,
+            new Function<Iterable<T>, Iterator<T>>() {
+              @Override public Iterator<T> apply(Iterable<T> it) { return 
it.iterator(); }
+            }));
+      }
+    }
+
+    @Override public boolean hasNext() {
+      init();
+      for (Iterator<T> it : iterators) {
+        if (it.hasNext()) {
+          return true;
+        }
+      }
+
+      return false;
+    }
+
+    @Override public List<T> next() {
+      init();
+      List<T> data = new ArrayList<T>(iterators.size());
+
+      for (Iterator<T> it : iterators) {
+        if (it.hasNext()) {
+          data.add(it.next());
+        } else {
+          overflowing.asMap().put(it, true);
+          data.add(defaultValue);
+        }
+      }
+
+      return data;
+    }
+
+    @Override public void remove() {
+      init();
+      for (Iterator<T> it : iterators) {
+        if (!overflowing.getUnchecked(it)) {
+          it.remove();
+        }
+      }
+    }
+
+    @Override public String toString() {
+      return Lists.newArrayList(iterables).toString();
+    }
+  }
+
+  /**
+   * Zips multiple iterables into one iterable that will return iterators to 
step over
+   * rows of the input iterators (columns).  The order of the returned values 
within each row will
+   * match the ordering of the input iterables. The iterators will iterate the 
length of the longest
+   * input iterable, filling other columns with {@code defaultValue}.
+   * The returned iterator is lazy, in that 'rows' are constructed as they are 
requested.
+   *
+   * @param iterables Columns to iterate over.
+   * @param defaultValue Default fill value when an input iterable is 
exhausted.
+   * @param <T> Type of value being iterated over.
+   * @return An iterator that iterates over rows of the input iterables.
+   */
+  public static <T> Iterable<List<T>> zip(final Iterable<Iterable<T>> 
iterables,
+      final T defaultValue) {
+
+    return new Iterable<List<T>>() {
+      @Override public Iterator<List<T>> iterator() {
+        return new ZippingIterator<T>(iterables, defaultValue);
+      }
+    };
+  }
+
+  /**
+   * Varargs convenience function to call {@link #zip(Iterable, Object)}.
+   *
+   * @param defaultValue Default fill value when an input iterable is 
exhausted.
+   * @param iterables Columns to iterate over.
+   * @param <T> Type of value being iterated over.
+   * @return An iterator that iterates over rows of the input iterables.
+   */
+  public static <T> Iterable<List<T>> zip(T defaultValue, Iterable<T>... 
iterables) {
+    return zip(Arrays.asList(iterables), defaultValue);
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/collections/Multimaps.java
----------------------------------------------------------------------
diff --git 
a/commons/src/main/java/com/twitter/common/collections/Multimaps.java 
b/commons/src/main/java/com/twitter/common/collections/Multimaps.java
new file mode 100644
index 0000000..c51b6fe
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/collections/Multimaps.java
@@ -0,0 +1,137 @@
+// 
=================================================================================================
+// Copyright 2011 Twitter, Inc.
+// 
-------------------------------------------------------------------------------------------------
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this work except in compliance with the License.
+// You may obtain a copy of the License in the LICENSE file, or at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
=================================================================================================
+
+package com.twitter.common.collections;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multiset;
+import com.google.common.collect.Ordering;
+import com.google.common.collect.Sets;
+
+/**
+ * Utility class for functions related to Multimaps in the java collections 
library.
+ *
+ * @author William Farner
+ */
+public final class Multimaps {
+
+  private Multimaps() {
+    // Utility.
+  }
+
+  /**
+   * Prunes a multimap based on a predicate, returning the pruned values.  The 
input map will be
+   * modified.
+   *
+   * @param map The multimap to prune.
+   * @param filterRule The pruning rule.  When the predicate returns {@code 
false} for an entry, it
+   *    will be pruned, otherwise it will be retained.
+   * @param <K> The key type in the multimap.
+   * @param <V> The value type in the multimap.
+   * @return A new multimap, containing the pruned keys/values.
+   */
+  public static <K, V> Multimap<K, V> prune(Multimap<K, V> map,
+      Predicate<? super Collection<V>> filterRule) {
+    Preconditions.checkNotNull(map);
+    Preconditions.checkNotNull(filterRule);
+    Multimap<K, V> pruned = ArrayListMultimap.create();
+    Iterator<Map.Entry<K, Collection<V>>> asMapItr = 
map.asMap().entrySet().iterator();
+    while (asMapItr.hasNext()) {
+      Map.Entry<K, Collection<V>> asMapEntry = asMapItr.next();
+      if (!filterRule.apply(asMapEntry.getValue())) {
+        pruned.putAll(asMapEntry.getKey(), asMapEntry.getValue());
+        asMapItr.remove();
+      }
+    }
+
+    return pruned;
+  }
+
+  private static final class AtLeastSize implements Predicate<Collection<?>> {
+    private final int minSize;
+
+    AtLeastSize(int minSize) {
+      Preconditions.checkArgument(minSize >= 0);
+      this.minSize = minSize;
+    }
+
+    @Override
+    public boolean apply(Collection<?> c) {
+      return c.size() >= minSize;
+    }
+  }
+
+  /**
+   * Convenience method to prune key/values pairs where the size of the value 
collection is below a
+   * threshold.
+   *
+   * @param map The multimap to prune.
+   * @param minSize The minimum size for retained value collections.
+   * @param <K> The key type in the multimap.
+   * @param <V> The value type in the multimap.
+   * @return A new multimap, containing the pruned keys/values.
+   * @throws IllegalArgumentException if minSize < 0
+   */
+  public static <K, V> Multimap<K, V> prune(Multimap<K, V> map, int minSize) {
+    return prune(map, new AtLeastSize(minSize));
+  }
+
+  /**
+   * Returns the set of keys associated with groups of a size greater than or 
equal to a given size.
+   *
+   * @param map The multimap to search.
+   * @param minSize The minimum size to return associated keys for.
+   * @param <K> The key type for the multimap.
+   * @return The keys associated with groups of size greater than or equal to 
{@code minSize}.
+   * @throws IllegalArgumentException if minSize < 0
+   */
+  public static <K> Set<K> getLargeGroups(Multimap<K, ?> map, int minSize) {
+    return Sets.newHashSet(
+        Maps.filterValues(map.asMap(), new AtLeastSize(minSize)).keySet());
+  }
+
+  /**
+   * Returns the set of keys associated with the largest values in the 
multimap.
+   *
+   * @param map The multimap to search.
+   * @param topValues Number of groupings to find the keys for.
+   * @return The keys associated with the largest groups, of maximum size 
{@code topValues}.
+   */
+  public static <K> Set<K> getLargestGroups(Multimap<K, ?> map, int topValues) 
{
+    Ordering<Multiset.Entry<K>> groupOrdering = new 
Ordering<Multiset.Entry<K>>() {
+      @Override
+      public int compare(Multiset.Entry<K> entry1, Multiset.Entry<K> entry2) {
+        return entry1.getCount() - entry2.getCount();
+        // overflow-safe, since sizes are nonnegative
+      }
+    };
+    Set<K> topKeys = Sets.newHashSetWithExpectedSize(topValues);
+    for (Multiset.Entry<K> entry
+         : groupOrdering.greatestOf(map.keys().entrySet(), topValues)) {
+      topKeys.add(entry.getElement());
+    }
+    return topKeys;
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/collections/Pair.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/collections/Pair.java 
b/commons/src/main/java/com/twitter/common/collections/Pair.java
new file mode 100644
index 0000000..5f2e3f6
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/collections/Pair.java
@@ -0,0 +1,130 @@
+// 
=================================================================================================
+// Copyright 2011 Twitter, Inc.
+// 
-------------------------------------------------------------------------------------------------
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this work except in compliance with the License.
+// You may obtain a copy of the License in the LICENSE file, or at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
=================================================================================================
+
+package com.twitter.common.collections;
+
+import javax.annotation.Nullable;
+
+import com.google.common.base.Function;
+
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+
+
+/**
+ * An immutable 2-tuple with value-equals semantics.
+ *
+ * @param <A> The type of the 1st item in the pair.
+ * @param <B> The type of the 2nd item in the pair.
+ *
+ * @author William Farner
+ */
+public class Pair<A, B> {
+
+  @Nullable
+  private final A first;
+  @Nullable
+  private final B second;
+
+  /**
+   * Creates a new pair.
+   *
+   * @param first The first value.
+   * @param second The second value.
+   */
+  public Pair(@Nullable A first, @Nullable B second) {
+    this.first = first;
+    this.second = second;
+  }
+
+  @Nullable
+  public A getFirst() {
+    return first;
+  }
+
+  @Nullable
+  public B getSecond() {
+    return second;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (o == this) { return true; }
+    if (!(o instanceof Pair)) { return false; }
+
+    Pair<?, ?> that = (Pair<?, ?>) o;
+    return new EqualsBuilder()
+        .append(this.first, that.first)
+        .append(this.second, that.second)
+        .isEquals();
+  }
+
+  @Override
+  public String toString() {
+    return String.format("(%s, %s)", getFirst(), getSecond());
+  }
+
+  @Override
+  public int hashCode() {
+    return new HashCodeBuilder()
+        .append(first)
+        .append(second)
+        .toHashCode();
+  }
+
+  /**
+   * Creates a function that can extract the first item of pairs of the given 
type parametrization.
+   *
+   * @param <S> The type of the 1st item in the pair.
+   * @param <T> The type of the 2nd item in the pair.
+   * @return A function that will extract the 1st item in a pair.
+   */
+  public static <S, T> Function<Pair<S, T>, S> first() {
+    return new Function<Pair<S, T>, S>() {
+      @Override public S apply(Pair<S, T> pair) {
+        return pair.first;
+      }
+    };
+  }
+
+  /**
+   * Creates a function that can extract the second item of pairs of the given 
type parametrization.
+   *
+   * @param <S> The type of the 1st item in the pair.
+   * @param <T> The type of the 2nd item in the pair.
+   * @return A function that will extract the 2nd item in a pair.
+   */
+  public static <S, T> Function<Pair<S, T>, T> second() {
+    return new Function<Pair<S, T>, T>() {
+      @Override public T apply(Pair<S, T> pair) {
+        return pair.second;
+      }
+    };
+  }
+
+  /**
+   * Convenience method to create a pair.
+   *
+   * @param a The first value.
+   * @param b The second value.
+   * @param <A> The type of the 1st item in the pair.
+   * @param <B> The type of the 2nd item in the pair.
+   * @return A new pair of [a, b].
+   */
+  public static <A, B> Pair<A, B> of(@Nullable A a, @Nullable B b) {
+    return new Pair<A, B>(a, b);
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/inject/Bindings.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/inject/Bindings.java 
b/commons/src/main/java/com/twitter/common/inject/Bindings.java
new file mode 100644
index 0000000..e0acb1a
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/inject/Bindings.java
@@ -0,0 +1,319 @@
+// 
=================================================================================================
+// Copyright 2011 Twitter, Inc.
+// 
-------------------------------------------------------------------------------------------------
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this work except in compliance with the License.
+// You may obtain a copy of the License in the LICENSE file, or at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
=================================================================================================
+
+package com.twitter.common.inject;
+
+import java.lang.annotation.Annotation;
+
+import javax.inject.Qualifier;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.inject.AbstractModule;
+import com.google.inject.Binder;
+import com.google.inject.BindingAnnotation;
+import com.google.inject.Key;
+import com.google.inject.Module;
+import com.google.inject.PrivateModule;
+import com.google.inject.TypeLiteral;
+import com.google.inject.binder.LinkedBindingBuilder;
+import com.google.inject.multibindings.Multibinder;
+import com.google.inject.name.Names;
+
+/**
+ * A utility that helps with guice bindings.
+ *
+ * @author John Sirois
+ */
+public final class Bindings {
+
+
+  private Bindings() {
+    // utility
+  }
+
+  /**
+   * Equivalent to calling {@code requireBinding(binder, Key.get(required, 
Names.named(namedKey)))}.
+   */
+  public static void requireNamedBinding(Binder binder, Class<?> required, 
String namedKey) {
+    requireBinding(binder, Key.get(Preconditions.checkNotNull(required),
+        Names.named(Preconditions.checkNotNull(namedKey))));
+  }
+
+  /**
+   * Equivalent to calling {@code requireBinding(binder, Key.get(required))}.
+   */
+  public static void requireBinding(Binder binder, Class<?> required) {
+    requireBinding(binder, Key.get(Preconditions.checkNotNull(required)));
+  }
+
+  /**
+   * Registers {@code required} as non-optional dependency in the {@link 
com.google.inject.Injector}
+   * associated with {@code binder}.
+   *
+   * @param binder A binder to require bindings against.
+   * @param required The dependency that is required.
+   */
+  public static void requireBinding(Binder binder, final Key<?> required) {
+    Preconditions.checkNotNull(binder);
+    Preconditions.checkNotNull(required);
+
+    binder.install(new AbstractModule() {
+      @Override protected void configure() {
+        requireBinding(required);
+      }
+    });
+  }
+
+  /**
+   * A convenient version of {@link #exposing(Iterable, 
com.google.inject.Module)} when you just
+   * want to expose a single binding.
+   */
+  public static Module exposing(Key<?> key, Module module) {
+    return exposing(ImmutableList.of(key), module);
+  }
+
+  /**
+   * Creates a module that hides all the given module's bindings and only 
exposes bindings for
+   * the given key.
+   *
+   * @param keys The keys of the bindings to expose.
+   * @param module The module to hide most bindings for.
+   * @return A limited visibility module.
+   */
+  public static Module exposing(final Iterable<? extends Key<?>> keys, final 
Module module) {
+    Preconditions.checkNotNull(keys);
+    Preconditions.checkNotNull(module);
+
+    return new PrivateModule() {
+      @Override protected void configure() {
+        install(module);
+        for (Key<?> key : keys) {
+          expose(key);
+        }
+      }
+    };
+  }
+
+  /**
+   * A guice binding helper that allows for any combination of Class, 
TypeLiteral or Key binding
+   * without forcing guiced implementation to provide all the overloaded 
binding methods they would
+   * otherwise have to.
+   *
+   * @param <T> The type this helper can be used to bind implementations for.
+   */
+  public interface BindHelper<T> {
+
+    /**
+     * Associates this BindHelper with an Injector instance.
+     *
+     * @param binder The binder for the injector implementations will be bound 
in.
+     * @return A binding builder that can be used to bind an implementation 
with.
+     */
+    LinkedBindingBuilder<T> with(Binder binder);
+  }
+
+  /**
+   * Creates a BindHelper for the given binding key that can be used to bind a 
single instance.
+   *
+   * @param key The binding key the returned BindHelper can be use to bind 
implementations for.
+   * @param <T> The type the returned BindHelper can be used to bind 
implementations for.
+   * @return A BindHelper that can be used to bind an implementation with.
+   */
+  public static <T> BindHelper<T> binderFor(final Key<T> key) {
+    return new BindHelper<T>() {
+      public LinkedBindingBuilder<T> with(Binder binder) {
+        return binder.bind(key);
+      }
+    };
+  }
+
+  /**
+   * Creates a BindHelper for the given type that can be used to add a binding 
of to a set.
+   *
+   * @param type The type the returned BindHelper can be use to bind 
implementations for.
+   * @param <T> The type the returned BindHelper can be used to bind 
implementations for.
+   * @return A BindHelper that can be used to bind an implementation with.
+   */
+  public static <T> BindHelper<T> multiBinderFor(final Class<T> type) {
+    return new BindHelper<T>() {
+      public LinkedBindingBuilder<T> with(Binder binder) {
+        return Multibinder.newSetBinder(binder, type).addBinding();
+      }
+    };
+  }
+
+  /**
+   * Checks that the given annotation instance is a {@link BindingAnnotation 
@BindingAnnotation}.
+   *
+   * @param annotation The annotation instance to check.
+   * @param <T> The type of the binding annotation.
+   * @return The checked binding annotation.
+   * @throws NullPointerException If the given {@code annotation} is null.
+   * @throws IllegalArgumentException If the given {@code annotation} is not a
+   *     {@literal @BindingAnnotation}.
+   */
+  public static <T extends Annotation> T checkBindingAnnotation(T annotation) {
+    Preconditions.checkNotNull(annotation);
+    checkBindingAnnotation(annotation.annotationType());
+    return annotation;
+  }
+
+  /**
+   * Checks that the given annotation type is a {@link BindingAnnotation 
@BindingAnnotation}.
+   *
+   * @param annotationType The annotation type to check.
+   * @param <T> The type of the binding annotation.
+   * @return The checked binding annotation type.
+   * @throws NullPointerException If the given {@code annotationType} is null.
+   * @throws IllegalArgumentException If the given {@code annotationType} is 
not a
+   *     {@literal @BindingAnnotation}.
+   */
+  public static <T extends Annotation> Class<T> 
checkBindingAnnotation(Class<T> annotationType) {
+    Preconditions.checkNotNull(annotationType);
+    boolean bindingAnnotation = 
annotationType.isAnnotationPresent(BindingAnnotation.class);
+    boolean qualifier = annotationType.isAnnotationPresent(Qualifier.class);
+    Preconditions.checkArgument(bindingAnnotation || qualifier,
+        "%s is not a @BindingAnnotation or @Qualifier", annotationType);
+    return annotationType;
+  }
+
+  /**
+   * A factory for binding {@link Key keys}.
+   */
+  public interface KeyFactory {
+
+    /**
+     * Creates plain un-annotated keys.
+     */
+    KeyFactory PLAIN = new KeyFactory() {
+      @Override public <T> Key<T> create(Class<T> type) {
+        return Key.get(type);
+      }
+      @Override public <T> Key<T> create(TypeLiteral<T> type) {
+        return Key.get(type);
+      }
+    };
+
+    /**
+     * Creates a key for the given type.
+     *
+     * @param type The type to create a key for.
+     * @param <T> The keyed type.
+     * @return A key.
+     */
+    <T> Key<T> create(Class<T> type);
+
+    /**
+     * Creates a key for the given type.
+     *
+     * @param type The type to create a key for.
+     * @param <T> The keyed type.
+     * @return A key.
+     */
+    <T> Key<T> create(TypeLiteral<T> type);
+  }
+
+  /**
+   * Creates a key factory that produces keys for a given annotation instance.
+   *
+   * @param annotation The annotation instance to apply to all keys.
+   * @return A key factory that creates annotated keys.
+   */
+  public static KeyFactory annotatedKeyFactory(final Annotation annotation) {
+    checkBindingAnnotation(annotation);
+    return new KeyFactory() {
+      @Override public <T> Key<T> create(Class<T> type) {
+        return Key.get(type, annotation);
+      }
+      @Override public <T> Key<T> create(TypeLiteral<T> type) {
+        return Key.get(type, annotation);
+      }
+    };
+  }
+
+  /**
+   * Creates a key factory that produces keys for a given annotation type.
+   *
+   * @param annotationType The annotation type to apply to all keys.
+   * @return A key factory that creates annotated keys.
+   */
+  public static KeyFactory annotatedKeyFactory(final Class<? extends 
Annotation> annotationType) {
+    checkBindingAnnotation(annotationType);
+    return new KeyFactory() {
+      @Override public <T> Key<T> create(Class<T> type) {
+        return Key.get(type, annotationType);
+      }
+      @Override public <T> Key<T> create(TypeLiteral<T> type) {
+        return Key.get(type, annotationType);
+      }
+    };
+  }
+
+  /**
+   * A utility that helps rebind keys.
+   */
+  public static final class Rebinder {
+    private final Binder binder;
+    private final KeyFactory bindToFactory;
+
+    /**
+     * Creates a Rebinder that links bindings to keys from the given {@code 
bindToFactory}.
+     *
+     * @param binder A binder to rebind keys in.
+     * @param bindToFactory A factory for the rebinding key.
+     */
+    public Rebinder(Binder binder, KeyFactory bindToFactory) {
+      this.binder = Preconditions.checkNotNull(binder);
+      this.bindToFactory = Preconditions.checkNotNull(bindToFactory);
+    }
+
+    /**
+     * Rebinds the given key to another, linking bindings.
+     *
+     * @param fromKey The source key to rebind.
+     * @return The key that {@code key} was rebound to.
+     */
+    public <T> Key<T> rebind(Key<T> fromKey) {
+      Key<T> toKey = bindToFactory.create(fromKey.getTypeLiteral());
+      binder.bind(toKey).to(fromKey);
+      requireBinding(binder, fromKey);
+      return toKey;
+    }
+  }
+
+  /**
+   * Creates a Rebinder that rebinds keys to the given annotation instance.
+   *
+   * @param binder A binder to rebind keys in.
+   * @param annotation The annotation instance to rebind keys to.
+   * @return A Rebinder targeting the given {@code annotationType}.
+   */
+  public static Rebinder rebinder(Binder binder, Annotation annotation) {
+    return new Rebinder(binder, annotatedKeyFactory(annotation));
+  }
+
+  /**
+   * Creates a Rebinder that rebinds keys to the given annotation type.
+   *
+   * @param binder A binder to rebind keys in.
+   * @param annotationType The annotation type to rebind keys to.
+   * @return A Rebinder targeting the given {@code annotationType}.
+   */
+  public static Rebinder rebinder(Binder binder, Class<? extends Annotation> 
annotationType) {
+    return new Rebinder(binder, annotatedKeyFactory(annotationType));
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/inject/DefaultProvider.java
----------------------------------------------------------------------
diff --git 
a/commons/src/main/java/com/twitter/common/inject/DefaultProvider.java 
b/commons/src/main/java/com/twitter/common/inject/DefaultProvider.java
new file mode 100644
index 0000000..8dc1c40
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/inject/DefaultProvider.java
@@ -0,0 +1,169 @@
+// 
=================================================================================================
+// Copyright 2011 Twitter, Inc.
+// 
-------------------------------------------------------------------------------------------------
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this work except in compliance with the License.
+// You may obtain a copy of the License in the LICENSE file, or at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
=================================================================================================
+
+package com.twitter.common.inject;
+
+import com.google.common.base.Preconditions;
+import com.google.inject.AbstractModule;
+import com.google.inject.Binder;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.Provider;
+import com.google.inject.TypeLiteral;
+import com.google.inject.name.Named;
+import com.google.inject.name.Names;
+
+/**
+ * Provider that has a default value which can be overridden.
+ *
+ * The intended use of this class is:
+ * <pre>
+ * Default installer:
+ *   bind(DefaultProvider.makeDefaultKey(Runnable.class, 
"mykey").toInstance(defaultRunnable);
+ *   DefaultProvider.bindOrElse(Runnable.class, "mykey", binder());
+ *
+ * Custom override:
+ *     bind(DefaultProvider.makeCustomKey(Runnable.class, 
"mykey")).toInstance(myCustomRunnable);
+ *
+ * Injection:
+ *     {@literal Inject} Named("myKey") Runnable runnable;
+ *
+ * </pre>
+ *
+ * @param <T> the type of object this provides
+ *
+ * @author William Farner
+ * @author John Sirois
+ */
+public class DefaultProvider<T> implements Provider<T> {
+  private static final String DEFAULT_BINDING_KEY_SUFFIX = "_default";
+  private static final String CUSTOM_BINDING_KEY_SUFFIX = "_custom";
+
+  private final Key<T> defaultProviderKey;
+  private final Key<T> customProviderKey;
+
+  private Injector injector;
+
+  public DefaultProvider(Key<T> defaultProviderKey, Key<T> customProviderKey) {
+    this.defaultProviderKey = Preconditions.checkNotNull(defaultProviderKey);
+    this.customProviderKey = Preconditions.checkNotNull(customProviderKey);
+    Preconditions.checkArgument(!defaultProviderKey.equals(customProviderKey));
+  }
+
+  @Inject
+  public void setInjector(Injector injector) {
+    this.injector = injector;
+  }
+
+  @Override
+  public T get() {
+     Preconditions.checkNotNull(injector);
+     return injector.getBindings().containsKey(customProviderKey)
+         ? injector.getInstance(customProviderKey)
+         : injector.getInstance(defaultProviderKey);
+  }
+
+  /**
+   * Creates a DefaultProvider and installs a new module to {@code binder}, 
which will serve as
+   * an indirection layer for swapping the default binding with a custom one.
+   *
+   * @param customBinding The custom binding key.
+   * @param defaultBinding The default binding key.
+   * @param exposedBinding The exposed binding key.
+   * @param binder The binder to install bindings to.
+   * @param <T> The type of binding to make.
+   */
+  public static <T> void bindOrElse(final Key<T> customBinding, final Key<T> 
defaultBinding,
+      final Key<T> exposedBinding, Binder binder) {
+    Preconditions.checkNotNull(customBinding);
+    Preconditions.checkNotNull(defaultBinding);
+    Preconditions.checkNotNull(exposedBinding);
+    Preconditions.checkArgument(!customBinding.equals(defaultBinding)
+        && !customBinding.equals(exposedBinding));
+
+    binder.install(new AbstractModule() {
+      @Override protected void configure() {
+        Provider<T> defaultProvider = new DefaultProvider<T>(defaultBinding, 
customBinding);
+        requestInjection(defaultProvider);
+        bind(exposedBinding).toProvider(defaultProvider);
+      }
+    });
+  }
+
+  /**
+   * Convenience function for creating and installing a DefaultProvider.  This 
will use internal
+   * suffixes to create names for the custom and default bindings.  When bound 
this way, callers
+   * should use one of the functions such as {@link 
#makeDefaultBindingKey(String)} to set default
+   * and custom bindings.
+   *
+   * @param type The type of object to bind.
+   * @param exposedKey The exposed key.
+   * @param binder The binder to install to.
+   * @param <T> The type of binding to make.
+   */
+  public static <T> void bindOrElse(TypeLiteral<T> type, String exposedKey, 
Binder binder) {
+    bindOrElse(Key.get(type, Names.named(makeCustomBindingKey(exposedKey))),
+        Key.get(type, Names.named(makeDefaultBindingKey(exposedKey))),
+        Key.get(type, Names.named(exposedKey)),
+        binder);
+  }
+
+  /**
+   * Convenience method for calls to {@link #bindOrElse(TypeLiteral, String, 
Binder)}, that are not
+   * binding a parameterized type.
+   *
+   * @param type The class of the object to bind.
+   * @param exposedKey The exposed key.
+   * @param binder The binder to install to.
+   * @param <T> The type of binding to make.
+   */
+  public static <T> void bindOrElse(Class<T> type, String exposedKey, Binder 
binder) {
+    bindOrElse(TypeLiteral.get(type), exposedKey, binder);
+  }
+
+  public static String makeDefaultBindingKey(String rootKey) {
+    return rootKey + DEFAULT_BINDING_KEY_SUFFIX;
+  }
+
+  public static Named makeDefaultBindingName(String rootKey) {
+    return Names.named(makeDefaultBindingKey(rootKey));
+  }
+
+  public static <T> Key<T> makeDefaultKey(TypeLiteral<T> type, String rootKey) 
{
+    return Key.get(type, makeDefaultBindingName(rootKey));
+  }
+
+  public static <T> Key<T> makeDefaultKey(Class<T> type, String rootKey) {
+    return makeDefaultKey(TypeLiteral.get(type), rootKey);
+  }
+
+  public static String makeCustomBindingKey(String rootKey) {
+    return rootKey + CUSTOM_BINDING_KEY_SUFFIX;
+  }
+
+  public static Named makeCustomBindingName(String rootKey) {
+    return Names.named(makeCustomBindingKey(rootKey));
+  }
+
+  public static <T> Key<T> makeCustomKey(Class<T> type, String rootKey) {
+    return Key.get(type, makeCustomBindingName(rootKey));
+  }
+
+  public static <T> Key<T> makeCustomKey(TypeLiteral<T> type, String rootKey) {
+    return Key.get(type, makeCustomBindingName(rootKey));
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/inject/ProviderMethodModule.java
----------------------------------------------------------------------
diff --git 
a/commons/src/main/java/com/twitter/common/inject/ProviderMethodModule.java 
b/commons/src/main/java/com/twitter/common/inject/ProviderMethodModule.java
new file mode 100644
index 0000000..64a4d3e
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/inject/ProviderMethodModule.java
@@ -0,0 +1,35 @@
+// 
=================================================================================================
+// Copyright 2011 Twitter, Inc.
+// 
-------------------------------------------------------------------------------------------------
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this work except in compliance with the License.
+// You may obtain a copy of the License in the LICENSE file, or at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
=================================================================================================
+
+package com.twitter.common.inject;
+
+import com.google.inject.AbstractModule;
+
+/**
+ * A convenience base class for modules that do all their binding via provider 
methods.
+ *
+ * @author John Sirois
+ */
+public abstract class ProviderMethodModule extends AbstractModule {
+
+  /**
+   * Does no binding; subclasses should implement provider methods.
+   */
+  @Override
+  protected final void configure() {
+    // noop
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/inject/TimedInterceptor.java
----------------------------------------------------------------------
diff --git 
a/commons/src/main/java/com/twitter/common/inject/TimedInterceptor.java 
b/commons/src/main/java/com/twitter/common/inject/TimedInterceptor.java
new file mode 100644
index 0000000..d0aabd7
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/inject/TimedInterceptor.java
@@ -0,0 +1,109 @@
+// 
=================================================================================================
+// Copyright 2011 Twitter, Inc.
+// 
-------------------------------------------------------------------------------------------------
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this work except in compliance with the License.
+// You may obtain a copy of the License in the LICENSE file, or at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
=================================================================================================
+
+package com.twitter.common.inject;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Method;
+
+import com.google.common.base.Preconditions;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.inject.Binder;
+import com.google.inject.matcher.Matchers;
+
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+import org.apache.commons.lang.StringUtils;
+
+import com.twitter.common.stats.SlidingStats;
+import com.twitter.common.stats.TimeSeriesRepository;
+
+/**
+ * A method interceptor that exports timing information for methods annotated 
with
+ * {@literal @Timed}.
+ *
+ * @author John Sirois
+ */
+public final class TimedInterceptor implements MethodInterceptor {
+
+  /**
+   * Marks a method as a target for timing.
+   */
+  @Retention(RetentionPolicy.RUNTIME)
+  @Target(ElementType.METHOD)
+  public @interface Timed {
+
+    /**
+     * The base name to export timing data with; empty to use the annotated 
method's name.
+     */
+    String value() default "";
+  }
+
+  private final LoadingCache<Method, SlidingStats> stats =
+      CacheBuilder.newBuilder().build(new CacheLoader<Method, SlidingStats>() {
+        @Override public SlidingStats load(Method method) {
+          return createStats(method);
+        }
+      });
+
+  private TimedInterceptor() {
+    // preserve for guice
+  }
+
+  private SlidingStats createStats(Method method) {
+    Timed timed = method.getAnnotation(Timed.class);
+    Preconditions.checkArgument(timed != null,
+        "TimedInterceptor can only be applied to @Timed methods");
+
+    String name = timed.value();
+    String statName = !StringUtils.isEmpty(name) ? name : method.getName();
+    return new SlidingStats(statName, "nanos");
+  }
+
+  @Override
+  public Object invoke(MethodInvocation methodInvocation) throws Throwable {
+    // TODO(John Sirois): consider including a SlidingRate tracking thrown 
exceptions
+    SlidingStats stat = stats.get(methodInvocation.getMethod());
+    long start = System.nanoTime();
+    try {
+      return methodInvocation.proceed();
+    } finally {
+      stat.accumulate(System.nanoTime() - start);
+    }
+  }
+
+  /**
+   * Installs an interceptor in a guice {@link com.google.inject.Injector}, 
enabling
+   * {@literal @Timed} method interception in guice-provided instances.  
Requires that a
+   * {@link TimeSeriesRepository} is bound elsewhere.
+   *
+   * @param binder a guice binder to require bindings against
+   */
+  public static void bind(Binder binder) {
+    Preconditions.checkNotNull(binder);
+
+    Bindings.requireBinding(binder, TimeSeriesRepository.class);
+
+    TimedInterceptor interceptor = new TimedInterceptor();
+    binder.requestInjection(interceptor);
+    binder.bindInterceptor(Matchers.any(), 
Matchers.annotatedWith(Timed.class), interceptor);
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/io/Base64ZlibCodec.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/io/Base64ZlibCodec.java 
b/commons/src/main/java/com/twitter/common/io/Base64ZlibCodec.java
new file mode 100644
index 0000000..e412659
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/io/Base64ZlibCodec.java
@@ -0,0 +1,156 @@
+package com.twitter.common.io;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.InflaterInputStream;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
+import com.google.common.io.ByteStreams;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.binary.Base64OutputStream;
+
+/**
+ * Utility class providing encoding and decoding methods to and from a string 
to a utf-8 encoded,
+ * zlib compressed, Base64 encoded representation of the string. For wider 
compatibility, the
+ * decoder can also automatically recognize GZIP (instead of plain zlib) 
compressed data too and
+ * decode it accordingly.
+ *
+ * @author Attila Szegedi
+ */
+public final class Base64ZlibCodec {
+  /**
+   * Thrown to indicate invalid data while decoding or unzipping.
+   *
+   * @author Attila Szegedi
+   */
+  public static class InvalidDataException extends Exception {
+    private static final long serialVersionUID = 1L;
+
+    public InvalidDataException(String message) {
+      super(message);
+    }
+
+    public InvalidDataException(String message, Throwable cause) {
+      super(message, cause);
+    }
+  }
+
+  /**
+   * Text encoding used by the Base64 output stream.
+   */
+  public static final String BASE64_TEXT_ENCODING = "ASCII";
+  private static final int ESTIMATED_PLAINTEXT_TO_ENCODED_RATIO = 4;
+
+  // Prefix all Base64-encoded, zlib compressed data must have
+  private static final byte[] ZLIB_HEADER_PREFIX = new byte[] { 120 };
+  // Prefix all Base64-encoded, GZIP compressed data must have
+  private static final byte[] GZIP_HEADER_PREFIX = new byte[] {31, -117, 8, 0, 
0, 0, 0, 0, 0 };
+  private static final int DIAGNOSTIC_PREFIX_LENGTH = 16;
+  // Text encoding for char-to-byte transformation before compressing a stack 
trace
+  private static final Charset TEXT_ENCODING = 
com.google.common.base.Charsets.UTF_8;
+
+  private Base64ZlibCodec() {
+    // Utility class
+  }
+
+  /**
+   * Decodes a string. In addition to zlib, it also automatically detects GZIP 
compressed data and
+   * adjusts accordingly.
+   *
+   * @param encoded the encoded string, represented as a byte array of 
ASCII-encoded characters
+   * @return the decoded string
+   * @throws InvalidDataException if the string can not be decoded.
+   */
+  public static byte[] decode(String encoded) throws InvalidDataException {
+    Preconditions.checkNotNull(encoded);
+    return decompress(new Base64().decode(encoded));
+  }
+
+  private static byte[] decompress(byte[] compressed) throws 
InvalidDataException {
+    byte[] bytes;
+    try {
+      final InputStream bin = new ByteArrayInputStream(compressed);
+      final InputStream zin;
+      if (startsWith(compressed, GZIP_HEADER_PREFIX)) {
+        zin = new GZIPInputStream(bin);
+      } else if (startsWith(compressed, ZLIB_HEADER_PREFIX)) {
+        zin = new InflaterInputStream(bin);
+      } else {
+        throw new Base64ZlibCodec.InvalidDataException("Value doesn't start 
with either GZIP or zlib header");
+      }
+      try {
+        bytes = ByteStreams.toByteArray(zin);
+      } finally {
+        zin.close();
+      }
+    } catch (IOException e) {
+      throw new Base64ZlibCodec.InvalidDataException("zlib/GZIP decoding 
error", e);
+    }
+    return bytes;
+  }
+
+  private static boolean startsWith(byte[] value, byte[] prefix) {
+    final int pl = prefix.length;
+    if (value.length < pl) {
+      return false;
+    }
+    for (int i = 0; i < pl; ++i) {
+      if (value[i] != prefix[i]) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Encodes a set of bytes.
+   *
+   * @param plain the non-encoded bytes
+   * @return the encoded string
+   */
+  public static String encode(byte[] plain) {
+    final ByteArrayOutputStream out = new ByteArrayOutputStream(plain.length
+        / ESTIMATED_PLAINTEXT_TO_ENCODED_RATIO);
+    final OutputStream w = getDeflatingEncodingStream(out);
+    try {
+      w.write(plain);
+      w.close();
+      return out.toString(BASE64_TEXT_ENCODING);
+    } catch (UnsupportedEncodingException e) {
+      throw reportUnsupportedEncoding();
+    } catch (IOException e) {
+      throw Throwables.propagate(e);
+    }
+  }
+
+  private static OutputStream getDeflatingEncodingStream(OutputStream out) {
+    return new DeflaterOutputStream(new Base64OutputStream(out, true,
+        Integer.MAX_VALUE, null));
+  }
+
+  /**
+   * Returns a writer that writes through to the specified output stream, 
utf-8 encoding,
+   * zlib compressing, and Base64 encoding its input along the way.
+   *
+   * @param out the output stream that receives the final output
+   * @return a writer for the input
+   */
+  public static Writer getEncodingWriter(OutputStream out) {
+    return new OutputStreamWriter(getDeflatingEncodingStream(out), 
TEXT_ENCODING);
+  }
+
+  private static AssertionError reportUnsupportedEncoding() {
+    return new AssertionError(String.format("JVM doesn't support the %s 
encoding", TEXT_ENCODING));
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/io/Codec.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/io/Codec.java 
b/commons/src/main/java/com/twitter/common/io/Codec.java
new file mode 100644
index 0000000..e3ef6b7
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/io/Codec.java
@@ -0,0 +1,56 @@
+// 
=================================================================================================
+// Copyright 2011 Twitter, Inc.
+// 
-------------------------------------------------------------------------------------------------
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this work except in compliance with the License.
+// You may obtain a copy of the License in the LICENSE file, or at:
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
=================================================================================================
+
+package com.twitter.common.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * A Codec represents a reversible encoding for a given type.  Codecs are able 
to both
+ * {@link #deserialize(java.io.InputStream) read} items from streams and
+ * {@link #serialize(Object, java.io.OutputStream) write} items to streams.
+ *
+ * <p> TODO(John Sirois): consider whether this interface should optionally 
support null items to be
+ * read and written.
+ *
+ * @param <T> The type of object the Codec can handle.
+ *
+ * @author John Sirois
+ */
+public interface Codec<T> {
+
+  /**
+   * Writes a representation of {@code item} to the {@code sink} that can be 
read back by
+   * {@link #deserialize(java.io.InputStream)}.
+   *
+   * @param item the item to serialize
+   * @param sink the stream to write the item out to
+   * @throws IOException if there is a problem serializing the item
+   */
+  void serialize(T item, OutputStream sink) throws IOException;
+
+  /**
+   * Reads an item from the {@code source} stream that was written by
+   * {@link #serialize(Object, java.io.OutputStream)}.
+   *
+   * @param source the stream to read an item from
+   * @return the deserialized item
+   * @throws IOException if there is a problem reading an item
+   */
+  T deserialize(InputStream source) throws IOException;
+}

Reply via email to