aurora-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From zma...@apache.org
Subject [33/37] aurora git commit: Import of Twitter Commons.
Date Tue, 25 Aug 2015 18:19:47 GMT
http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/CharacterParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/CharacterParser.java b/commons/src/main/java/com/twitter/common/args/parsers/CharacterParser.java
new file mode 100644
index 0000000..9a5f9ad
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/CharacterParser.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.args.parsers;
+
+import com.twitter.common.args.ArgParser;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Character parser.
+ *
+ * @author William Farner
+ */
+@ArgParser
+public class CharacterParser extends NonParameterizedTypeParser<Character> {
+  @Override
+  public Character doParse(String raw) {
+    checkArgument(raw.length() == 1,
+        "String " + raw + " cannot be assigned to a character.");
+    return raw.charAt(0);
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/ClassParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/ClassParser.java b/commons/src/main/java/com/twitter/common/args/parsers/ClassParser.java
new file mode 100644
index 0000000..bf32dc1
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/ClassParser.java
@@ -0,0 +1,51 @@
+// =================================================================================================
+// 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.args.parsers;
+
+import java.lang.reflect.Type;
+import java.util.List;
+
+import com.google.common.base.Preconditions;
+
+import com.twitter.common.args.ArgParser;
+import com.twitter.common.args.ParserOracle;
+import com.twitter.common.args.TypeUtil;
+
+/**
+ * Class parser.
+ *
+ * @author William Farner
+ */
+@ArgParser
+public class ClassParser extends TypeParameterizedParser<Class<?>> {
+
+  public ClassParser() {
+    super(1);
+  }
+
+  @Override
+  public Class<?> doParse(ParserOracle parserOracle, String raw, final List<Type> typeParams) {
+    Class<?> rawClassType = TypeUtil.getRawType(typeParams.get(0));
+    try {
+      Class<?> actualClass = Class.forName(raw);
+      Preconditions.checkArgument(rawClassType.isAssignableFrom(actualClass));
+      return actualClass;
+    } catch (ClassNotFoundException e) {
+      throw new IllegalArgumentException("Could not find class " + raw);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/DateParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/DateParser.java b/commons/src/main/java/com/twitter/common/args/parsers/DateParser.java
new file mode 100644
index 0000000..651004b
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/DateParser.java
@@ -0,0 +1,44 @@
+// =================================================================================================
+// 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.args.parsers;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import com.twitter.common.args.ArgParser;
+
+/**
+ * Date parser.
+ *
+ * @author William Farner
+ */
+@ArgParser
+public class DateParser extends NonParameterizedTypeParser<Date> {
+
+  private static final String FORMAT = "MM/dd/yyyy HH:mm";
+  private static final SimpleDateFormat SIMPLE_FORMAT = new SimpleDateFormat(FORMAT);
+
+  @Override
+  public Date doParse(String raw) {
+    try {
+      return SIMPLE_FORMAT.parse(raw);
+    } catch (ParseException e) {
+      throw new IllegalArgumentException("Failed to parse " + raw + " in format " + FORMAT);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/DoubleParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/DoubleParser.java b/commons/src/main/java/com/twitter/common/args/parsers/DoubleParser.java
new file mode 100644
index 0000000..1965625
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/DoubleParser.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.args.parsers;
+
+import com.twitter.common.args.ArgParser;
+
+/**
+ * Double parser.
+ *
+ * @author William Farner
+ */
+@ArgParser
+public class DoubleParser extends NumberParser<Double> {
+  @Override
+  Double parseNumber(String raw) {
+    return Double.parseDouble(raw);
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/DurationParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/DurationParser.java b/commons/src/main/java/com/twitter/common/args/parsers/DurationParser.java
new file mode 100644
index 0000000..bcb4bf8
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/DurationParser.java
@@ -0,0 +1,83 @@
+// =================================================================================================
+// 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.args.parsers;
+
+import java.lang.reflect.Type;
+import java.util.Collections;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import com.google.common.base.Preconditions;
+
+import com.twitter.common.args.ParserOracle;
+import com.twitter.common.quantity.Amount;
+import com.twitter.common.quantity.Time;
+
+/**
+ * Utility class for parsing durations of the form "1d23h59m59s" (as well as subvariants, i.e.
+ * "10h5s" would also work, as would "2d"). These values are useful representations in HTTP query
+ * parameters for durations.
+ *
+ */
+public class DurationParser extends TypeParameterizedParser<Amount<?, ?>> {
+
+  private static final String SUFFIXES = "dhms";
+  private static final Time[] TIME_UNITS = {Time.DAYS, Time.HOURS, Time.MINUTES, Time.SECONDS};
+
+  public DurationParser() {
+    super(2);
+  }
+
+  @Override
+  Amount<?, ?> doParse(ParserOracle parserOracle, String raw, List<Type> paramParsers)
+      throws IllegalArgumentException {
+    Type secondParamClass = paramParsers.get(1);
+    Preconditions.checkArgument(
+        secondParamClass == Time.class,
+        String.format("Expected %s for "
+            + "second type parameter, but got got %s", Time.class.getName(),
+            secondParamClass));
+    return parse(raw);
+  }
+
+  /**
+   * Parses a duration of the form "1d23h59m59s" (as well as subvariants, i.e. "10h5s" would also
+   * work, as would "2d").
+   *
+   * @param spec the textual duration specification
+   * @return the parsed form
+   * @throws IllegalArgumentException if the specification can not be parsed
+   */
+  public static Amount<Long, Time> parse(String spec) {
+    long time = 0L;
+    final List<Object> tokens = Collections.list(new StringTokenizer(spec, SUFFIXES, true));
+    Preconditions.checkArgument(tokens.size() > 1);
+    for (int i = 1; i < tokens.size(); i += 2) {
+      final String token = (String) tokens.get(i);
+      Preconditions.checkArgument(token.length() == 1, "Too long suffix '%s'", token);
+      final int suffixIndex = SUFFIXES.indexOf(token.charAt(0));
+      Preconditions.checkArgument(suffixIndex != -1, "Unrecognized suffix '%s'", token);
+      try {
+        final int value = Integer.parseInt((String) tokens.get(i - 1));
+        time += Amount.of(value, TIME_UNITS[suffixIndex]).as(Time.SECONDS);
+      } catch (NumberFormatException e) {
+        Preconditions.checkArgument(false, "Invalid number %s", tokens.get(i - 1));
+      }
+    }
+    return Amount.of(time, Time.SECONDS);
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/EnumParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/EnumParser.java b/commons/src/main/java/com/twitter/common/args/parsers/EnumParser.java
new file mode 100644
index 0000000..1741b7d
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/EnumParser.java
@@ -0,0 +1,39 @@
+// =================================================================================================
+// 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.args.parsers;
+
+import java.lang.reflect.Type;
+
+import com.twitter.common.args.ArgParser;
+import com.twitter.common.args.Parser;
+import com.twitter.common.args.ParserOracle;
+
+/**
+ * An {@link Enum} parser that matches enum values via {@link Enum#valueOf(Class, String)}.
+ *
+ * @author John Sirois
+ */
+@ArgParser
+public class EnumParser<T extends Enum<T>> implements Parser<T> {
+
+  @Override
+  public T parse(ParserOracle parserOracle, Type type, String raw) throws IllegalArgumentException {
+    @SuppressWarnings("unchecked")
+    Class<T> enumClass = (Class<T>) type;
+    return Enum.valueOf(enumClass, raw);
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/FileParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/FileParser.java b/commons/src/main/java/com/twitter/common/args/parsers/FileParser.java
new file mode 100644
index 0000000..a3cf1b2
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/FileParser.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.args.parsers;
+
+import java.io.File;
+
+import com.twitter.common.args.ArgParser;
+
+/**
+ * File parser.
+ *
+ * @author William Farner
+ */
+@ArgParser
+public class FileParser extends NonParameterizedTypeParser<File> {
+  @Override
+  public File doParse(String raw) {
+    return new File(raw);
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/FloatParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/FloatParser.java b/commons/src/main/java/com/twitter/common/args/parsers/FloatParser.java
new file mode 100644
index 0000000..3330bba
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/FloatParser.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.args.parsers;
+
+import com.twitter.common.args.ArgParser;
+
+/**
+ * Float parser.
+ *
+ * @author William Farner
+ */
+@ArgParser
+public class FloatParser extends NumberParser<Float> {
+  @Override
+  Float parseNumber(String raw) {
+    return Float.parseFloat(raw);
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/InetSocketAddressParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/InetSocketAddressParser.java b/commons/src/main/java/com/twitter/common/args/parsers/InetSocketAddressParser.java
new file mode 100644
index 0000000..584240b
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/InetSocketAddressParser.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.args.parsers;
+
+import java.net.InetSocketAddress;
+
+import com.twitter.common.args.ArgParser;
+import com.twitter.common.net.InetSocketAddressHelper;
+
+/**
+ * InetSocketAddress parser.
+ *
+ * @author William Farner
+ */
+@ArgParser
+public class InetSocketAddressParser extends NonParameterizedTypeParser<InetSocketAddress> {
+  @Override
+  public InetSocketAddress doParse(String raw) {
+    return InetSocketAddressHelper.parse(raw);
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/IntegerParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/IntegerParser.java b/commons/src/main/java/com/twitter/common/args/parsers/IntegerParser.java
new file mode 100644
index 0000000..c4bcd23
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/IntegerParser.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.args.parsers;
+
+import com.twitter.common.args.ArgParser;
+
+/**
+ * Integer parser.
+ *
+ * @author William Farner
+ */
+@ArgParser
+public class IntegerParser extends NumberParser<Integer> {
+  @Override
+  Integer parseNumber(String raw) {
+    return Integer.parseInt(raw);
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/ListParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/ListParser.java b/commons/src/main/java/com/twitter/common/args/parsers/ListParser.java
new file mode 100644
index 0000000..79434c0
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/ListParser.java
@@ -0,0 +1,55 @@
+// =================================================================================================
+// 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.args.parsers;
+
+import java.lang.reflect.Type;
+import java.util.List;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.reflect.TypeToken;
+
+import com.twitter.common.args.ArgParser;
+import com.twitter.common.args.Parser;
+import com.twitter.common.args.ParserOracle;
+import com.twitter.common.args.Parsers;
+
+/**
+ * List parser.
+ *
+ * @author William Farner
+ */
+@ArgParser
+public class ListParser extends TypeParameterizedParser<List<?>> {
+
+  public ListParser() {
+    super(1);
+  }
+
+  @Override
+  List<?> doParse(final ParserOracle parserOracle, String raw, final List<Type> typeParams) {
+    final Type listType = typeParams.get(0);
+    final Parser<?> parser = parserOracle.get(TypeToken.of(listType));
+    return ImmutableList.copyOf(Iterables.transform(Parsers.MULTI_VALUE_SPLITTER.split(raw),
+        new Function<String, Object>() {
+          @Override public Object apply(String raw) {
+            return parser.parse(parserOracle, listType, raw);
+          }
+        }));
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/LongParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/LongParser.java b/commons/src/main/java/com/twitter/common/args/parsers/LongParser.java
new file mode 100644
index 0000000..83c6752
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/LongParser.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.args.parsers;
+
+import com.twitter.common.args.ArgParser;
+
+/**
+ * Long parser.
+ *
+ * @author William Farner
+ */
+@ArgParser
+public class LongParser extends NumberParser<Long> {
+  @Override
+  Long parseNumber(String raw) {
+    return Long.parseLong(raw);
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/MapParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/MapParser.java b/commons/src/main/java/com/twitter/common/args/parsers/MapParser.java
new file mode 100644
index 0000000..19de492
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/MapParser.java
@@ -0,0 +1,71 @@
+// =================================================================================================
+// 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.args.parsers;
+
+import java.lang.reflect.Type;
+import java.util.List;
+import java.util.Map;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.reflect.TypeToken;
+
+import com.twitter.common.args.ArgParser;
+import com.twitter.common.args.Parser;
+import com.twitter.common.args.ParserOracle;
+import com.twitter.common.args.Parsers;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Map parser.
+ *
+ * @author William Farner
+ */
+@ArgParser
+public class MapParser extends TypeParameterizedParser<Map<?, ?>> {
+
+  private static final Splitter KEY_VALUE_SPLITTER =
+      Splitter.on("=").trimResults().omitEmptyStrings();
+
+  public MapParser() {
+    super(2);
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  Map<?, ?> doParse(ParserOracle parserOracle, String raw, List<Type> typeParams) {
+    Type keyType = typeParams.get(0);
+    Parser<?> keyParser = parserOracle.get(TypeToken.of(keyType));
+
+    Type valueType = typeParams.get(1);
+    Parser<?> valueParser = parserOracle.get(TypeToken.of(valueType));
+
+    ImmutableMap.Builder<Object, Object> map = ImmutableMap.builder();
+    for (String keyAndValue : Parsers.MULTI_VALUE_SPLITTER.split(raw)) {
+      List<String> fields = ImmutableList.copyOf(KEY_VALUE_SPLITTER.split(keyAndValue));
+      checkArgument(fields.size() == 2,
+          "Failed to parse key/value pair " + keyAndValue);
+
+      map.put(keyParser.parse(parserOracle, keyType, fields.get(0)),
+              valueParser.parse(parserOracle, valueType, fields.get(1)));
+    }
+
+    return map.build();
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/NonParameterizedTypeParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/NonParameterizedTypeParser.java b/commons/src/main/java/com/twitter/common/args/parsers/NonParameterizedTypeParser.java
new file mode 100644
index 0000000..187de17
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/NonParameterizedTypeParser.java
@@ -0,0 +1,44 @@
+// =================================================================================================
+// 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.args.parsers;
+
+import java.lang.reflect.Type;
+
+import com.twitter.common.args.Parser;
+import com.twitter.common.args.ParserOracle;
+
+/**
+ * Base class for parsers of types that are not parameterized.
+ *
+ * @author William Farner
+ */
+public abstract class NonParameterizedTypeParser<T> implements Parser<T> {
+
+  /**
+   * Performs the parsing of the raw string.
+   *
+   * @param raw Value to parse.
+   * @return The parsed value.
+   * @throws IllegalArgumentException If the value could not be parsed into the target type.
+   */
+  public abstract T doParse(String raw) throws IllegalArgumentException;
+
+  @Override
+  public T parse(ParserOracle parserOracle, Type type, String raw) throws IllegalArgumentException {
+    return doParse(raw);
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/NumberParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/NumberParser.java b/commons/src/main/java/com/twitter/common/args/parsers/NumberParser.java
new file mode 100644
index 0000000..4214f59
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/NumberParser.java
@@ -0,0 +1,44 @@
+// =================================================================================================
+// 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.args.parsers;
+
+/**
+ * Parser that handles common functionality for parsing numbers.
+ *
+ * @author William Farner
+ */
+public abstract class NumberParser<T extends Number> extends NonParameterizedTypeParser<T> {
+
+  /**
+   * Performs the actual parsing of the value into the target type.
+   *
+   * @param raw Raw value to parse.
+   * @return The parsed value.
+   * @throws NumberFormatException If the raw value does not represent a valid number of the target
+   *    type.
+   */
+  abstract T parseNumber(String raw) throws NumberFormatException;
+
+  @Override
+  public T doParse(String raw) throws IllegalArgumentException {
+    try {
+      return parseNumber(raw);
+    } catch (NumberFormatException e) {
+      throw new IllegalArgumentException(String.format("Invalid value: " + e.getMessage()));
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/PairParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/PairParser.java b/commons/src/main/java/com/twitter/common/args/parsers/PairParser.java
new file mode 100644
index 0000000..5356321
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/PairParser.java
@@ -0,0 +1,60 @@
+// =================================================================================================
+// 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.args.parsers;
+
+import java.lang.reflect.Type;
+import java.util.List;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.reflect.TypeToken;
+
+import com.twitter.common.args.ArgParser;
+import com.twitter.common.args.Parser;
+import com.twitter.common.args.ParserOracle;
+import com.twitter.common.args.Parsers;
+import com.twitter.common.collections.Pair;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Pair parser.
+ *
+ * @author William Farner
+ */
+@ArgParser
+public class PairParser extends TypeParameterizedParser<Pair<?, ?>> {
+
+  public PairParser() {
+    super(2);
+  }
+
+  @Override
+  Pair<?, ?> doParse(ParserOracle parserOracle, String raw, List<Type> typeParams) {
+    Type leftType = typeParams.get(0);
+    Parser<?> leftParser = parserOracle.get(TypeToken.of(leftType));
+
+    Type rightType = typeParams.get(1);
+    Parser<?> rightParser = parserOracle.get(TypeToken.of(rightType));
+
+    List<String> parts = ImmutableList.copyOf(Parsers.MULTI_VALUE_SPLITTER.split(raw));
+    checkArgument(parts.size() == 2,
+        "Only two values may be specified for a pair, you gave " + parts.size());
+
+    return Pair.of(leftParser.parse(parserOracle, leftType, parts.get(0)),
+                   rightParser.parse(parserOracle, rightType, parts.get(1)));
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/PatternParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/PatternParser.java b/commons/src/main/java/com/twitter/common/args/parsers/PatternParser.java
new file mode 100644
index 0000000..1834628
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/PatternParser.java
@@ -0,0 +1,38 @@
+// =================================================================================================
+// Copyright 2013 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.args.parsers;
+
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import com.twitter.common.args.ArgParser;
+
+/**
+ * A regular expression parser.
+ */
+@ArgParser
+public class PatternParser extends NonParameterizedTypeParser<Pattern> {
+
+  @Override
+  public Pattern doParse(String raw) throws IllegalArgumentException {
+    try {
+      return Pattern.compile(raw);
+    } catch (PatternSyntaxException e) {
+      throw new IllegalArgumentException(e);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/RangeParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/RangeParser.java b/commons/src/main/java/com/twitter/common/args/parsers/RangeParser.java
new file mode 100644
index 0000000..0cba553
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/RangeParser.java
@@ -0,0 +1,33 @@
+package com.twitter.common.args.parsers;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Range;
+
+import com.twitter.common.args.ArgParser;
+
+/**
+ * A parser that handles closed ranges. For the input "4-6", it will capture [4, 5, 6].
+ */
+@ArgParser
+public class RangeParser extends NonParameterizedTypeParser<Range<Integer>> {
+  @Override
+  public Range<Integer> doParse(String raw) throws IllegalArgumentException {
+    ImmutableList<String> numbers =
+        ImmutableList.copyOf(Splitter.on('-').omitEmptyStrings().split(raw));
+    try {
+      int from = Integer.parseInt(numbers.get(0));
+      int to = Integer.parseInt(numbers.get(1));
+      if (numbers.size() != 2) {
+        throw new IllegalArgumentException("Failed to parse the range:" + raw);
+      }
+      if (to < from) {
+        return Range.closed(to, from);
+      } else {
+        return Range.closed(from, to);
+      }
+    } catch (NumberFormatException e) {
+      throw new IllegalArgumentException("Failed to parse the range:" + raw, e);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/SetParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/SetParser.java b/commons/src/main/java/com/twitter/common/args/parsers/SetParser.java
new file mode 100644
index 0000000..fecaeb2
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/SetParser.java
@@ -0,0 +1,57 @@
+// =================================================================================================
+// 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.args.parsers;
+
+import java.lang.reflect.Type;
+import java.util.List;
+import java.util.Set;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.reflect.TypeToken;
+
+import com.twitter.common.args.ArgParser;
+import com.twitter.common.args.Parser;
+import com.twitter.common.args.ParserOracle;
+import com.twitter.common.args.Parsers;
+
+/**
+ * Set parser.
+ *
+ * @author William Farner
+ */
+@ArgParser
+public class SetParser extends TypeParameterizedParser<Set<?>> {
+
+  public SetParser() {
+    super(1);
+  }
+
+  @Override
+  Set<?> doParse(final ParserOracle parserOracle, String raw, List<Type> typeParams) {
+    final Type setType = typeParams.get(0);
+    final Parser<?> parser = parserOracle.get(TypeToken.of(setType));
+
+    return ImmutableSet.copyOf(Iterables.transform(Parsers.MULTI_VALUE_SPLITTER.split(raw),
+        new Function<String, Object>() {
+          @Override public Object apply(String raw) {
+            return parser.parse(parserOracle, setType, raw);
+          }
+        }));
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/ShortParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/ShortParser.java b/commons/src/main/java/com/twitter/common/args/parsers/ShortParser.java
new file mode 100644
index 0000000..b13386c
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/ShortParser.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.args.parsers;
+
+import com.twitter.common.args.ArgParser;
+
+/**
+ * Short parser.
+ *
+ * @author William Farner
+ */
+@ArgParser
+public class ShortParser extends NumberParser<Short> {
+  @Override
+  Short parseNumber(String raw) {
+    return Short.parseShort(raw);
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/StringParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/StringParser.java b/commons/src/main/java/com/twitter/common/args/parsers/StringParser.java
new file mode 100644
index 0000000..a403917
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/StringParser.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.args.parsers;
+
+import com.twitter.common.args.ArgParser;
+
+/**
+ * String parser.
+ *
+ * @author William Farner
+ */
+@ArgParser
+public class StringParser extends NonParameterizedTypeParser<String> {
+  @Override
+  public String doParse(String raw) {
+    return raw;
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/TypeParameterizedParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/TypeParameterizedParser.java b/commons/src/main/java/com/twitter/common/args/parsers/TypeParameterizedParser.java
new file mode 100644
index 0000000..7ded11f
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/TypeParameterizedParser.java
@@ -0,0 +1,68 @@
+// =================================================================================================
+// 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.args.parsers;
+
+import java.lang.reflect.Type;
+import java.util.List;
+
+import com.twitter.common.args.Parser;
+import com.twitter.common.args.ParserOracle;
+import com.twitter.common.args.TypeUtil;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Parser that makes implementation of parsers for parameterized types simpler.
+ *
+ * @param <T> The raw type this parser can parse.
+ *
+ * @author William Farner
+ */
+public abstract class TypeParameterizedParser<T> implements Parser<T> {
+
+  private final int typeParamCount;
+
+  /**
+   * Creates a new type parameterized parser.
+   *
+   * @param typeParamCount Strict number of type parameters to allow on the assigned type.
+   */
+  TypeParameterizedParser(int typeParamCount) {
+    this.typeParamCount = typeParamCount;
+  }
+
+  /**
+   * Performs the actual parsing.
+   *
+   * @param parserOracle The registered parserOracle for delegation.
+   * @param raw The raw value to parse.
+   * @param typeParams The captured actual type parameters for {@code T}.
+   * @return The parsed value.
+   * @throws IllegalArgumentException If the value could not be parsed.
+   */
+  abstract T doParse(ParserOracle parserOracle, String raw, List<Type> typeParams)
+      throws IllegalArgumentException;
+
+  @Override public T parse(ParserOracle parserOracle, Type type, String raw) {
+    List<Type> typeParams = TypeUtil.getTypeParams(type);
+    checkArgument(typeParams.size() == typeParamCount, String.format(
+        "Expected %d type parameters for %s but got %d",
+        typeParamCount, type, typeParams.size()));
+
+    return doParse(parserOracle, raw, typeParams);
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/URIParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/URIParser.java b/commons/src/main/java/com/twitter/common/args/parsers/URIParser.java
new file mode 100644
index 0000000..fce84c0
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/URIParser.java
@@ -0,0 +1,39 @@
+// =================================================================================================
+// 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.args.parsers;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import com.twitter.common.args.ArgParser;
+
+/**
+ * URI parser.
+ *
+ * @author William Farner
+ */
+@ArgParser
+public class URIParser extends NonParameterizedTypeParser<URI> {
+  @Override
+  public URI doParse(String raw) {
+    try {
+      return new URI(raw);
+    } catch (URISyntaxException e) {
+      throw new IllegalArgumentException("Malformed URI " + raw + ", " + e.getMessage());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/URLParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/URLParser.java b/commons/src/main/java/com/twitter/common/args/parsers/URLParser.java
new file mode 100644
index 0000000..33bcd49
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/URLParser.java
@@ -0,0 +1,39 @@
+// =================================================================================================
+// 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.args.parsers;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import com.twitter.common.args.ArgParser;
+
+/**
+ * URL parser.
+ *
+ * @author William Farner
+ */
+@ArgParser
+public class URLParser extends NonParameterizedTypeParser<URL> {
+  @Override
+  public URL doParse(String raw) {
+    try {
+      return new URL(raw);
+    } catch (MalformedURLException e) {
+      throw new IllegalArgumentException("Malformed URL " + raw + ", " + e.getMessage());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/args/parsers/UnitParser.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/args/parsers/UnitParser.java b/commons/src/main/java/com/twitter/common/args/parsers/UnitParser.java
new file mode 100644
index 0000000..0ccba62
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/args/parsers/UnitParser.java
@@ -0,0 +1,57 @@
+// =================================================================================================
+// 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.args.parsers;
+
+import java.util.EnumSet;
+import java.util.Map;
+
+import com.google.common.base.Functions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Maps;
+
+import com.twitter.common.args.ArgParser;
+import com.twitter.common.quantity.Data;
+import com.twitter.common.quantity.Time;
+import com.twitter.common.quantity.Unit;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Unit parser.
+ * Units are matched (case sensitively) against the result of {@link Unit#toString()}.
+ */
+@ArgParser
+public class UnitParser extends NonParameterizedTypeParser<Unit<?>> {
+
+  private final Map<String, Unit<?>> unitValues;
+
+  public UnitParser() {
+    unitValues = Maps.uniqueIndex(
+        ImmutableList.<Unit<?>>builder().add(Time.values()).add(Data.values()).build(),
+        Functions.toStringFunction());
+  }
+
+  @Override
+  public Unit<?> doParse(String raw) {
+    Unit<?> unit = unitValues.get(raw);
+
+    checkArgument(unit != null, String.format(
+        "No Units found matching %s, options: (Time): %s, (Data): %s",
+        raw, EnumSet.allOf(Time.class), EnumSet.allOf(Data.class)));
+    return unit;
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/CachingSupplier.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/base/CachingSupplier.java b/commons/src/main/java/com/twitter/common/base/CachingSupplier.java
new file mode 100644
index 0000000..561dfec
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/base/CachingSupplier.java
@@ -0,0 +1,71 @@
+// =================================================================================================
+// 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.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+
+import com.twitter.common.quantity.Amount;
+import com.twitter.common.quantity.Time;
+import com.twitter.common.util.Clock;
+
+/**
+ * A supplier that caches responses from an underling supplier, expiring the cached value after
+ * a fixed expiration time.
+ *
+ * @param <T> Supplied value type.
+ *
+ * @author William Farner
+ */
+public class CachingSupplier<T> implements Supplier<T> {
+
+  private final Supplier<T> wrapped;
+  private final long expirationNanos;
+  private final Clock clock;
+
+  private long lastFetchNanos = -1;
+  private T cachedValue;
+
+  /**
+   * Creates a new caching supplier.
+   *
+   * @param wrapped The supplier to delegate fetches to.
+   * @param expiration The maximum amount of time that a response from {@code supplier} will be
+   *   cached for.  The expiration must be positive.
+   */
+  public CachingSupplier(Supplier<T> wrapped, Amount<Long, Time> expiration) {
+    this(wrapped, expiration, Clock.SYSTEM_CLOCK);
+  }
+
+  @VisibleForTesting
+  CachingSupplier(Supplier<T> wrapped, Amount<Long, Time> expiration, Clock clock) {
+    this.wrapped = Preconditions.checkNotNull(wrapped);
+    this.expirationNanos = Preconditions.checkNotNull(expiration).as(Time.NANOSECONDS);
+    Preconditions.checkArgument(expiration.getValue() > 0, "Expiration must be positive.");
+    this.clock = Preconditions.checkNotNull(clock);
+  }
+
+  @Override
+  public synchronized T get() {
+    if ((lastFetchNanos == -1) || (clock.nowNanos() - lastFetchNanos > expirationNanos)) {
+      cachedValue = wrapped.get();
+      lastFetchNanos = clock.nowNanos();
+    }
+
+    return cachedValue;
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/CallableExceptionalSupplier.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/base/CallableExceptionalSupplier.java b/commons/src/main/java/com/twitter/common/base/CallableExceptionalSupplier.java
new file mode 100644
index 0000000..0d3692c
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/base/CallableExceptionalSupplier.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.base;
+
+import java.util.concurrent.Callable;
+
+/**
+ * A supplier that may also be called.
+ *
+ * @param <T> The supplier type.
+ * @param <E> Supplier exception type.
+ *
+ * @author John Sirois
+ */
+public abstract class CallableExceptionalSupplier<T, E extends Exception>
+    implements ExceptionalSupplier<T, E>, Callable<T> {
+
+  @Override public T call() throws Exception {
+    return get();
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/Closure.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/base/Closure.java b/commons/src/main/java/com/twitter/common/base/Closure.java
new file mode 100644
index 0000000..94ae264
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/base/Closure.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 closure that does not throw any checked exceptions.
+ *
+ * @param <T> Closure value type.
+ *
+ * @author John Sirois
+ */
+public interface Closure<T> extends ExceptionalClosure<T, RuntimeException> {
+  // convenience typedef
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/Closures.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/base/Closures.java b/commons/src/main/java/com/twitter/common/base/Closures.java
new file mode 100644
index 0000000..f8dc61c
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/base/Closures.java
@@ -0,0 +1,136 @@
+// =================================================================================================
+// 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.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Utilities for dealing with Closures.
+ *
+ * @author John Sirois
+ */
+public final class Closures {
+
+  private static final Closure<?> NOOP = new Closure<Object>() {
+    @Override public void execute(Object item) {
+      // noop
+    }
+  };
+
+  private Closures() {
+    // utility
+  }
+
+  /**
+   * Converts a closure into a function returning {@code null}.
+   */
+  public static <T> Function<T, Void> asFunction(final ExceptionalClosure<T, ?> closure) {
+    checkNotNull(closure);
+
+    // CHECKSTYLE:OFF IllegalCatch
+    return new Function<T, Void>() {
+      @Override public Void apply(T item) {
+        try {
+          closure.execute(item);
+        } catch (Exception e) {
+          Throwables.propagate(e);
+        }
+        return null;
+      }
+    };
+    // CHECKSTYLE:ON IllegalCatch
+  }
+
+  /**
+   * Varargs equivalent of {@link #combine(Iterable)}.
+   *
+   * @param closures Closures to combine.
+   * @param <T> Type accepted by the closures.
+   * @return A single closure that will fan out all calls to {@link Closure#execute(Object)} to
+   *    the wrapped closures.
+   */
+  public static <T> Closure<T> combine(Closure<T>... closures) {
+    return combine(ImmutableList.copyOf(closures));
+  }
+
+  /**
+   * Combines multiple closures into a single closure, whose calls are replicated sequentially
+   * in the order that they were provided.
+   * If an exception is encountered from a closure it propagates to the top-level closure and the
+   * remaining closures are not executed.
+   *
+   * @param closures Closures to combine.
+   * @param <T> Type accepted by the closures.
+   * @return A single closure that will fan out all calls to {@link Closure#execute(Object)} to
+   *    the wrapped closures.
+   */
+  public static <T> Closure<T> combine(Iterable<Closure<T>> closures) {
+    checkNotNull(closures);
+    checkArgument(Iterables.all(closures, Predicates.notNull()));
+
+    final Iterable<Closure<T>> closuresCopy = ImmutableList.copyOf(closures);
+
+    return new Closure<T>() {
+      @Override public void execute(T item) {
+        for (Closure<T> closure : closuresCopy) {
+          closure.execute(item);
+        }
+      }
+    };
+  }
+
+  /**
+   * Applies a filter to a closure, such that the closure will only be called when the filter is
+   * satisfied (returns {@code true}}.
+   *
+   * @param filter Filter to determine when {@code closure} is called.
+   * @param closure Closure to filter.
+   * @param <T> Type handled by the filter and the closure.
+   * @return A filtered closure.
+   */
+  public static <T> Closure<T> filter(final Predicate<T> filter, final Closure<T> closure) {
+    checkNotNull(filter);
+    checkNotNull(closure);
+
+    return new Closure<T>() {
+      @Override public void execute(T item) {
+        if (filter.apply(item)) {
+          closure.execute(item);
+        }
+      }
+    };
+  }
+
+  /**
+   * Returns a closure that will do nothing.
+   *
+   * @param <T> The closure argument type.
+   * @return A closure that does nothing.
+   */
+  @SuppressWarnings("unchecked")
+  public static <T> Closure<T> noop() {
+    return (Closure<T>) NOOP;
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/Command.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/base/Command.java b/commons/src/main/java/com/twitter/common/base/Command.java
new file mode 100644
index 0000000..306b552
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/base/Command.java
@@ -0,0 +1,26 @@
+// =================================================================================================
+// 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 command that does not throw any checked exceptions.
+ *
+ * @author John Sirois
+ */
+public interface Command extends ExceptionalCommand<RuntimeException> {
+  // convenience typedef
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/Commands.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/base/Commands.java b/commons/src/main/java/com/twitter/common/base/Commands.java
new file mode 100644
index 0000000..7d8d782
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/base/Commands.java
@@ -0,0 +1,80 @@
+// =================================================================================================
+// 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;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Utility functions for working with commands.
+ *
+ * @author John Sirois
+ */
+public final class Commands {
+
+  /**
+   * A command that does nothing when executed.
+   */
+  public static final Command NOOP = new Command() {
+    @Override public void execute() {
+      // noop
+    }
+  };
+
+  private Commands() {
+    // utility
+  }
+
+  /**
+   * Converts a command into a supplier returning null.
+   *
+   * @return A supplier whose {@link com.twitter.common.base.Supplier#get()} will cause the given
+   *         {@code command} to be executed and {@code null} to be returned.
+   */
+  public static <E extends Exception> ExceptionalSupplier<Void, E> asSupplier(
+      final ExceptionalCommand<E> command) {
+    checkNotNull(command);
+
+    return new ExceptionalSupplier<Void, E>() {
+      @Override public Void get() throws E {
+        command.execute();
+        return null;
+      }
+    };
+  }
+
+  /**
+   * Combines multiple {@code commands} into a single command. A {@link RuntimeException} thrown
+   * during the execution of one of the commands will prevent the subsequent commands from being
+   * executed.
+   *
+   * @param commands Commands to compound.
+   * @return A command whose {@link Command#execute()} will cause the given {@code commands} to be
+   *         executed serially.
+   */
+  public static Command compound(Iterable<Command> commands) {
+    final ImmutableList<Command> executableCommands = ImmutableList.copyOf(commands);
+    return new Command() {
+      @Override public void execute() {
+        for (Command command : executableCommands) {
+          command.execute();
+        }
+      }
+    };
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/Either.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/base/Either.java b/commons/src/main/java/com/twitter/common/base/Either.java
new file mode 100644
index 0000000..9b556a3
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/base/Either.java
@@ -0,0 +1,345 @@
+package com.twitter.common.base;
+
+import javax.annotation.Nullable;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Optional;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+/**
+ * A value of one of two possible types.
+ *
+ * <p>Often Either processing is used as an alternative exception flow control.  In these uses the
+ * left type represents failure by convention and the right type the success path result.
+ *
+ * @param <L> The left type.
+ * @param <R> The right type.
+ */
+public final class Either<L, R> {
+  private final Optional<L> left;
+  private final Optional<R> right;
+
+  private Either(Optional<L> left, Optional<R> right) {
+    this.left = left;
+    this.right = right;
+  }
+
+  /**
+   * Turns a left into a right and vice-versa.
+   *
+   * @return A new swapped either instance.
+   */
+  public Either<R, L> swap() {
+    return new Either<R, L>(right, left);
+  }
+
+  /**
+   * Returns an optional the will be {@link Optional#isPresent() present} is this is a left
+   * instance.
+   *
+   * @return An optional value for the left.
+   */
+  public Optional<L> left() {
+    return left;
+  }
+
+  /**
+   * Returns an optional the will be {@link Optional#isPresent() present} is this is a right
+   * instance.
+   *
+   * @return An optional value for the right.
+   */
+  public Optional<R> right() {
+    return right;
+  }
+
+  /**
+   * Returns {@code true} if this is a left instance.
+   *
+   * @return {@code true} if this is a left.
+   */
+  public boolean isLeft() {
+    return left().isPresent();
+  }
+
+  /**
+   * Returns {@code true} if this is a right instance.
+   *
+   * @return {@code true} if this is a right.
+   */
+  public boolean isRight() {
+    return right().isPresent();
+  }
+
+  /**
+   * Returns the underlying value if this is a left; otherwise, throws.
+   *
+   * @return The underlying value.
+   * @throws IllegalStateException if this is a right instance.
+   */
+  public L getLeft() {
+    return left().get();
+  }
+
+  /**
+   * Returns the underlying value if this is a right; otherwise, throws.
+   *
+   * @return The underlying value.
+   * @throws IllegalStateException if this is a right instance.
+   */
+  public R getRight() {
+    return right().get();
+  }
+
+  /**
+   * If this is a left, maps its value into a new left; otherwise just returns this right.
+   *
+   * @param transformer The transformation to apply to the left value.
+   * @param <M> The type a left value will be mapped to.
+   * @return The mapped left or else the right.
+   */
+  public <M> Either<M, R> mapLeft(Function<? super L, M> transformer) {
+    if (isLeft()) {
+      return left(transformer.apply(getLeft()));
+    } else {
+      @SuppressWarnings("unchecked") // I am a right so my left is never accessible
+      Either<M, R> self = (Either<M, R>) this;
+      return self;
+    }
+  }
+
+  /**
+   * If this is a right, maps its value into a new right; otherwise just returns this left.
+   *
+   * @param transformer The transformation to apply to the left value.
+   * @param <M> The type a right value will be mapped to.
+   * @return The mapped right or else the left.
+   */
+  public <M> Either<L, M> mapRight(Function<? super R, M> transformer) {
+    if (isRight()) {
+      return right(transformer.apply(getRight()));
+    } else {
+      @SuppressWarnings("unchecked") // I am a left so my right is never accessible
+      Either<L, M> self = (Either<L, M>) this;
+      return self;
+    }
+  }
+
+  /**
+   * Can transform either a left or a right into a result.
+   *
+   * @param <L> The left type.
+   * @param <R> The right type.
+   * @param <T> The transformation result type.
+   */
+  public abstract static class Transformer<L, R, T> implements Function<Either<L, R>, T> {
+
+    /**
+     * Maps left values to a result.
+     *
+     * @param left the left value to map.
+     * @return The mapped value.
+     */
+    public abstract T mapLeft(L left);
+
+    /**
+     * Maps right values to a result.
+     *
+     * @param right the right value to map.
+     * @return The mapped value.
+     */
+    public abstract T mapRight(R right);
+
+    @Override
+    public final T apply(Either<L, R> either) {
+      return either.map(this);
+    }
+  }
+
+  /**
+   * Creates a transformer from left and right transformation functions.
+   *
+   * @param leftTransformer A transformer to process left values.
+   * @param rightTransformer A transformer to process right values.
+   * @param <L> The left type.
+   * @param <R> The right type.
+   * @param <T> The transformation result type.
+   * @return A new transformer composed of left and right transformer functions.
+   */
+  public static <L, R, T> Transformer<L, R, T> transformer(
+      final Function<? super L, T> leftTransformer,
+      final Function<? super R, T> rightTransformer) {
+
+    return new Transformer<L, R, T>() {
+      @Override public T mapLeft(L item) {
+        return leftTransformer.apply(item);
+      }
+      @Override public T mapRight(R item) {
+        return rightTransformer.apply(item);
+      }
+    };
+  }
+
+  /**
+   * Transforms this either instance to a value regardless of whether it is a left or a right.
+   *
+   * @param transformer The transformer to map this either instance.
+   * @param <T> The type the transformer produces.
+   * @return A value mapped by the transformer from this left or right instance.
+   */
+  public <T> T map(final Transformer<? super L, ? super R, T> transformer) {
+    if (isLeft()) {
+      return transformer.mapLeft(getLeft());
+    } else {
+      return transformer.mapRight(getRight());
+    }
+  }
+
+  @Override
+  public boolean equals(@Nullable Object o) {
+    if (!(o instanceof Either)) {
+      return false;
+    }
+    Either<?, ?> other = (Either<?, ?>) o;
+    return Objects.equal(left, other.left)
+        && Objects.equal(right, other.right);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hashCode(left, right);
+  }
+
+  @Override
+  public String toString() {
+    if (isLeft()) {
+      return String.format("Left(%s)", getLeft());
+    } else {
+      return String.format("Right(%s)", getRight());
+    }
+  }
+
+  /**
+   * Creates a left either instance.
+   *
+   * @param value The left value to wrap - may not be null.
+   * @param <L> The left type.
+   * @param <R> The right type.
+   * @return A left either instance wrapping {@code value}.
+   */
+  public static <L, R> Either<L, R> left(L value) {
+    return new Either<L, R>(Optional.of(value), Optional.<R>absent());
+  }
+
+  /**
+   * Creates a right either instance.
+   *
+   * @param value The right value to wrap - may not be null.
+   * @param <L> The left type.
+   * @param <R> The right type.
+   * @return A right either instance wrapping {@code value}.
+   */
+  public static <L, R> Either<L, R> right(R value) {
+    return new Either<L, R>(Optional.<L>absent(), Optional.of(value));
+  }
+
+  /**
+   * Extracts all the lefts from a sequence of eithers lazily.
+   *
+   * @param results A sequence of either's to process.
+   * @param <L> The left type.
+   * @param <R> The right type.
+   * @return A lazy iterable that will produce the lefts present in results in order.
+   */
+  public static <L, R> Iterable<L> lefts(Iterable<Either<L, R>> results) {
+    return Optional.presentInstances(Iterables.transform(results,
+        new Function<Either<L, R>, Optional<L>>() {
+          @Override public Optional<L> apply(Either<L, R> item) {
+            return item.left();
+          }
+        }));
+  }
+
+  /**
+   * Extracts all the rights from a sequence of eithers lazily.
+   *
+   * @param results A sequence of either's to process.
+   * @param <L> The left type.
+   * @param <R> The right type.
+   * @return A lazy iterable that will produce the rights present in results in order.
+   */
+  public static <L, R> Iterable<R> rights(Iterable<Either<L, R>> results) {
+    return Optional.presentInstances(Iterables.transform(results,
+        new Function<Either<L, R>, Optional<R>>() {
+          @Override public Optional<R> apply(Either<L, R> item) {
+            return item.right();
+          }
+        }));
+  }
+
+  /**
+   * A convenience method equivalent to calling {@code guard(work, exceptionType)}.
+   */
+  public static <X extends Exception, R> Either<X, R> guard(
+      Class<X> exceptionType,
+      ExceptionalSupplier<R, X> work) {
+
+    @SuppressWarnings("unchecked")
+    Either<X, R> either = guard(work, exceptionType);
+    return either;
+  }
+
+  /**
+   * A convenience method equivalent to calling
+   * {@code guard(Lists.asList(execpetionType, rest), work)}.
+   */
+  public static <X extends Exception, R> Either<X, R> guard(
+      ExceptionalSupplier<R, X> work,
+      Class<? extends X> exceptionType,
+      Class<? extends X>... rest) {
+
+    return guard(Lists.asList(exceptionType, rest), work);
+  }
+
+  /**
+   * Thrown when guarded work throws an unguarded exception.  The {@link #getCause() cause} will
+   * contain the original unguarded exception.
+   */
+  public static class UnguardedException extends RuntimeException {
+    public UnguardedException(Throwable cause) {
+      super(cause);
+    }
+  }
+
+  /**
+   * Converts work that can throw exceptions into an either with a left exception base type.  This
+   * can be useful to fold an exception throwing library call into an either processing style
+   * pipeline.
+   *
+   * @param exceptionTypes The expected exception types.
+   * @param work The work to perform to get a result produce an error.
+   * @param <X> The base error type.
+   * @param <R> The success type.
+   * @return An either wrapping the result of performing {@code work}.
+   * @throws UnguardedException if work throws an unguarded exception type.
+   */
+  public static <X extends Exception, R> Either<X, R> guard(
+      Iterable<Class<? extends X>> exceptionTypes,
+      ExceptionalSupplier<R, X> work) {
+
+    try {
+      return right(work.get());
+    // We're explicitly dealing with generic exception types here by design.
+    // SUPPRESS CHECKSTYLE RegexpSinglelineJava
+    } catch (Exception e) {
+      for (Class<? extends X> exceptionType : exceptionTypes) {
+        if (exceptionType.isInstance(e)) {
+          X exception = exceptionType.cast(e);
+          return left(exception);
+        }
+      }
+      throw new UnguardedException(e);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/86a547b9/commons/src/main/java/com/twitter/common/base/ExceptionTransporter.java
----------------------------------------------------------------------
diff --git a/commons/src/main/java/com/twitter/common/base/ExceptionTransporter.java b/commons/src/main/java/com/twitter/common/base/ExceptionTransporter.java
new file mode 100644
index 0000000..5bd540e
--- /dev/null
+++ b/commons/src/main/java/com/twitter/common/base/ExceptionTransporter.java
@@ -0,0 +1,87 @@
+// =================================================================================================
+// 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.Function;
+
+/**
+ * A utility for transporting checked exceptions across boundaries that do not allow for checked
+ * exception propagation.
+ *
+ * @param <E> The type of checked exception the ExceptionTransported can transport
+ *
+ * @author John Sirois
+ */
+public class ExceptionTransporter<E extends Exception> {
+
+  /**
+   * An exception wrapper used to transport checked exceptions.  Never leaves an
+   * {@link ExceptionTransporter#guard(com.google.common.base.Function)} call.
+   */
+  private static final class TransportingException extends RuntimeException {
+    private TransportingException(Exception cause) {
+      super("It is a usage error to see this message!", cause);
+    }
+  }
+
+  /**
+   * Guards a unit of work that internally can generate checked exceptions.  Callers wrap up the
+   * work in a function that rethrows any checked exceptions using the supplied
+   * ExceptionTransporter.  Guard will ensure the original exception is unwrapped an re-thrown.
+   *
+   * @param work The unit of work that guards its checked exceptions.
+   * @param <T> The type returned by the unit of work when it successfully completes.
+   * @param <X> The type of checked exception that the unit of work wishes to guard.
+   * @return the result of the unit of work if no excpetions are thrown
+   * @throws X when the unit of work uses the ExceptionTransporter to throw a checked exception
+   */
+  public static <T, X extends Exception> T guard(Function<ExceptionTransporter<X>, T> work)
+    throws X {
+
+    try {
+      return work.apply(new ExceptionTransporter<X>());
+    } catch (TransportingException e) {
+      @SuppressWarnings("unchecked")
+      X cause = (X) e.getCause();
+      throw cause;
+    }
+  }
+
+  /**
+   * Throws the given {@code checked} exception across a boundary that does not allow checked
+   * exceptions.  Although a RuntimeException is returned by this method signature, the method never
+   * actually completes normally.  The return type does allow the following usage idiom however:
+   * <pre>
+   * public String apply(ExceptionTransporter transporter) {
+   *   try {
+   *     return doChecked();
+   *   } catch (CheckedException e) {
+   *     // Although transport internally throws and does not return, we satisfy the compiler that
+   *     // our method returns a value or throws by pretending to throw the RuntimeException that
+   *     // never actually gets returned by transporter.transport(...)
+   *     throw transporter.transport(e);
+   *   }
+   * }
+   * </pre>
+   *
+   * @param checked The checked exception to transport.
+   * @return A RuntimeException that can be thrown to satisfy the compiler at the call site
+   */
+  public RuntimeException transport(E checked) {
+    throw new TransportingException(checked);
+  }
+}


Mime
View raw message