http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons-args/src/main/java/com/twitter/common/args/apt/CmdLineProcessor.java
----------------------------------------------------------------------
diff --git 
a/commons-args/src/main/java/com/twitter/common/args/apt/CmdLineProcessor.java 
b/commons-args/src/main/java/com/twitter/common/args/apt/CmdLineProcessor.java
deleted file mode 100644
index 0e793ef..0000000
--- 
a/commons-args/src/main/java/com/twitter/common/args/apt/CmdLineProcessor.java
+++ /dev/null
@@ -1,677 +0,0 @@
-/**
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License 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.apt;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.Writer;
-import java.lang.annotation.Annotation;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.annotation.Nullable;
-import javax.annotation.processing.AbstractProcessor;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.annotation.processing.RoundEnvironment;
-import javax.annotation.processing.SupportedOptions;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.Elements;
-import javax.lang.model.util.SimpleAnnotationValueVisitor6;
-import javax.lang.model.util.SimpleTypeVisitor6;
-import javax.lang.model.util.Types;
-import javax.tools.Diagnostic.Kind;
-import javax.tools.FileObject;
-import javax.tools.StandardLocation;
-
-import com.google.common.base.Function;
-import com.google.common.base.Functions;
-import com.google.common.base.Optional;
-import com.google.common.base.Predicates;
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.base.Throwables;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
-import com.twitter.common.args.Arg;
-import com.twitter.common.args.ArgParser;
-import com.twitter.common.args.CmdLine;
-import com.twitter.common.args.Parser;
-import com.twitter.common.args.Positional;
-import com.twitter.common.args.Verifier;
-import com.twitter.common.args.VerifierFor;
-import com.twitter.common.args.apt.Configuration.ParserInfo;
-
-import static com.twitter.common.args.apt.Configuration.ArgInfo;
-import static com.twitter.common.args.apt.Configuration.VerifierInfo;
-
-/**
- * Processes {@literal @CmdLine} annotated fields and {@literal @ArgParser} and
- * {@literal @VerifierFor} parser and verifier registrations and stores 
configuration data listing
- * these fields, parsers and verifiers on the classpath for discovery via
- * {@link com.twitter.common.args.apt.Configuration#load()}.
- *
- * <p>Supports an apt option useful for some build setups that create 
monolithic jars aggregating
- * many library jars, one or more of which have embedded arg definitions 
themselves.  By adding the
- * following flag to a javac invocation:
- * <code>-Acom.twitter.common.args.apt.CmdLineProcessor.main</code>
- * you signal this apt processor that the compilation target is a leaf target 
that will comprise one
- * or more executable mains (as opposed to a library jar).  As a result, the 
embedded arg
- * definitions generated will occupy a special resource that is always checked 
for first during
- * runtime arg parsing.
- */
-@SupportedOptions({
-    CmdLineProcessor.MAIN_OPTION,
-    CmdLineProcessor.CHECK_LINKAGE_OPTION
-})
-public class CmdLineProcessor extends AbstractProcessor {
-  static final String MAIN_OPTION =
-      "com.twitter.common.args.apt.CmdLineProcessor.main";
-  static final String CHECK_LINKAGE_OPTION =
-      "com.twitter.common.args.apt.CmdLineProcessor.check_linkage";
-
-  private static final Function<Class<?>, String> GET_NAME = new 
Function<Class<?>, String>() {
-    @Override public String apply(Class<?> type) {
-      return type.getName();
-    }
-  };
-
-  private final Supplier<Configuration> configSupplier =
-      Suppliers.memoize(new Supplier<Configuration>() {
-        @Override public Configuration get() {
-          try {
-            Configuration configuration = Configuration.load();
-            for (ArgInfo argInfo : configuration.positionalInfo()) {
-              configBuilder.addPositionalInfo(argInfo);
-            }
-            for (ArgInfo argInfo : configuration.optionInfo()) {
-              configBuilder.addCmdLineArg(argInfo);
-            }
-            for (ParserInfo parserInfo : configuration.parserInfo()) {
-              configBuilder.addParser(parserInfo);
-            }
-            for (VerifierInfo verifierInfo : configuration.verifierInfo()) {
-              configBuilder.addVerifier(verifierInfo);
-            }
-            return configuration;
-          } catch (IOException e) {
-            error("Problem loading existing flags on compile time classpath: 
%s",
-                Throwables.getStackTraceAsString(e));
-            return null;
-          }
-        }
-      });
-
-  private final Configuration.Builder configBuilder = new 
Configuration.Builder();
-  private final ImmutableSet.Builder<String> contributingClassNamesBuilder = 
ImmutableSet.builder();
-
-  private Types typeUtils;
-  private Elements elementUtils;
-  private boolean isMain;
-  private boolean isCheckLinkage;
-
-  private static boolean getBooleanOption(Map<String, String> options, String 
name,
-      boolean defaultValue) {
-
-    if (!options.containsKey(name)) {
-      return defaultValue;
-    }
-
-    // We want to map the presence of a boolean option without a value to 
indicate true, giving the
-    // following accepted boolean option formats:
-    // -Afoo -> true
-    // -Afoo=false -> false
-    // -Afoo=true -> true
-
-    String isOption = options.get(name);
-    return (isOption == null) || Boolean.parseBoolean(isOption);
-  }
-
-  @Override
-  public void init(ProcessingEnvironment processingEnv) {
-    super.init(processingEnv);
-
-    typeUtils = processingEnv.getTypeUtils();
-    elementUtils = processingEnv.getElementUtils();
-
-    Map<String, String> options = processingEnv.getOptions();
-    isMain = getBooleanOption(options, MAIN_OPTION, false);
-    isCheckLinkage = getBooleanOption(options, CHECK_LINKAGE_OPTION, true);
-  }
-
-  @Override
-  public SourceVersion getSupportedSourceVersion() {
-    return SourceVersion.latest();
-  }
-
-  @Override
-  public Set<String> getSupportedAnnotationTypes() {
-    return ImmutableSet.copyOf(Iterables.transform(
-        ImmutableList.of(Positional.class, CmdLine.class, ArgParser.class, 
VerifierFor.class),
-        GET_NAME));
-  }
-
-  @Override
-  public boolean process(Set<? extends TypeElement> annotations, 
RoundEnvironment roundEnv) {
-    try {
-      @Nullable Configuration classpathConfiguration = configSupplier.get();
-
-      Set<? extends Element> parsers = getAnnotatedElements(roundEnv, 
ArgParser.class);
-      contributingClassNamesBuilder.addAll(extractClassNames(parsers));
-      @Nullable Set<String> parsedTypes = 
getParsedTypes(classpathConfiguration, parsers);
-
-      Set<? extends Element> cmdlineArgs = getAnnotatedElements(roundEnv, 
CmdLine.class);
-      
contributingClassNamesBuilder.addAll(extractEnclosingClassNames(cmdlineArgs));
-      Set<? extends Element> positionalArgs = getAnnotatedElements(roundEnv, 
Positional.class);
-      
contributingClassNamesBuilder.addAll(extractEnclosingClassNames(positionalArgs));
-
-      ImmutableSet<? extends Element> invalidArgs =
-          Sets.intersection(cmdlineArgs, positionalArgs).immutableCopy();
-      if (!invalidArgs.isEmpty()) {
-        error("An Arg cannot be annotated with both @CmdLine and @Positional, 
found bad Arg "
-            + "fields: %s", invalidArgs);
-      }
-
-      for (ArgInfo cmdLineInfo : processAnnotatedArgs(parsedTypes, 
cmdlineArgs, CmdLine.class)) {
-        configBuilder.addCmdLineArg(cmdLineInfo);
-      }
-
-      for (ArgInfo positionalInfo
-          : processAnnotatedArgs(parsedTypes, positionalArgs, 
Positional.class)) {
-
-        configBuilder.addPositionalInfo(positionalInfo);
-      }
-      checkPositionalArgsAreLists(roundEnv);
-
-      processParsers(parsers);
-
-      Set<? extends Element> verifiers = getAnnotatedElements(roundEnv, 
VerifierFor.class);
-      contributingClassNamesBuilder.addAll(extractClassNames(verifiers));
-      processVerifiers(verifiers);
-
-      if (roundEnv.processingOver()) {
-        if (classpathConfiguration != null
-            && (!classpathConfiguration.isEmpty() || 
!configBuilder.isEmpty())) {
-
-          @Nullable Resource cmdLinePropertiesResource =
-              openCmdLinePropertiesResource(classpathConfiguration);
-          if (cmdLinePropertiesResource != null) {
-            Writer writer = cmdLinePropertiesResource.getWriter();
-            try {
-              configBuilder.build(classpathConfiguration).store(writer,
-                  "Generated via apt by " + getClass().getName());
-            } finally {
-              closeQuietly(writer);
-            }
-
-            writeResourceMapping(contributingClassNamesBuilder.build(),
-                cmdLinePropertiesResource.getResource());
-          }
-        }
-      }
-    // TODO(John Sirois): Investigate narrowing this catch - its not clear 
there is any need to be
-    // so general.
-    // SUPPRESS CHECKSTYLE RegexpSinglelineJava
-    } catch (RuntimeException e) {
-      // Catch internal errors - when these bubble more useful queued error 
messages are lost in
-      // some javac implementations.
-      error("Unexpected error completing annotation processing:\n%s",
-          Throwables.getStackTraceAsString(e));
-    }
-    return true;
-  }
-
-  private void writeResourceMapping(
-      Set<String> contributingClassNames,
-      FileObject cmdLinePropertiesResourcePath) {
-
-    // TODO(John Sirois): Lift the compiler resource-mappings writer to its 
own class/artifact to be
-    // re-used by other apt processors: 
https://github.com/twitter/commons/issues/319
-
-    // NB: javac rejects a package name with illegal package name characters 
like '-' so we just
-    // pass the empty package and the fully qualified resource file name.
-    @Nullable Resource resource = openResource("",
-        "META-INF/compiler/resource-mappings/" + getClass().getName());
-    if (resource != null) {
-      PrintWriter writer = new PrintWriter(resource.getWriter());
-      writer.printf("resources by class name:\n");
-      writer.printf("%d items\n", contributingClassNames.size());
-      try {
-        for (String className : contributingClassNames) {
-          writer.printf("%s -> %s\n", className, 
cmdLinePropertiesResourcePath.toUri().getPath());
-        }
-      } finally {
-        closeQuietly(writer);
-      }
-    }
-  }
-
-  private static final Function<Element, Element> EXTRACT_ENCLOSING_CLASS =
-      new Function<Element, Element>() {
-        @Override public Element apply(Element element) {
-          return element.getEnclosingElement();
-        }
-      };
-
-  private final Function<Element, String> extractClassName = new 
Function<Element, String>() {
-    @Override public String apply(Element element) {
-      return getBinaryName((TypeElement) element);
-    }
-  };
-
-  private final Function<Element, String> extractEnclosingClassName =
-      Functions.compose(extractClassName, EXTRACT_ENCLOSING_CLASS);
-
-  private Iterable<String> extractEnclosingClassNames(Iterable<? extends 
Element> elements) {
-    return Iterables.transform(elements, extractEnclosingClassName);
-  }
-
-  private Iterable<String> extractClassNames(Iterable<? extends Element> 
elements) {
-    return Iterables.transform(elements, extractClassName);
-  }
-
-  private void closeQuietly(Closeable closeable) {
-    try {
-      closeable.close();
-    } catch (IOException e) {
-      log(Kind.MANDATORY_WARNING, "Failed to close %s: %s", closeable, e);
-    }
-  }
-
-  private void checkPositionalArgsAreLists(RoundEnvironment roundEnv) {
-    for (Element positionalArg : getAnnotatedElements(roundEnv, 
Positional.class)) {
-      @Nullable TypeMirror typeArgument =
-          getTypeArgument(positionalArg.asType(), typeElement(Arg.class));
-      if ((typeArgument == null)
-          || !typeUtils.isSubtype(typeElement(List.class).asType(), 
typeArgument)) {
-        error("Found @Positional %s %s.%s that is not a List",
-            positionalArg.asType(), positionalArg.getEnclosingElement(), 
positionalArg);
-      }
-    }
-  }
-
-  @Nullable
-  private Set<String> getParsedTypes(@Nullable Configuration configuration,
-      Set<? extends Element> parsers) {
-
-    if (!isCheckLinkage) {
-      return null;
-    }
-
-    Iterable<String> parsersFor = 
Optional.presentInstances(Iterables.transform(parsers,
-        new Function<Element, Optional<String>>() {
-          @Override public Optional<String> apply(Element parser) {
-            TypeMirror parsedType = getTypeArgument(parser.asType(), 
typeElement(Parser.class));
-            if (parsedType == null) {
-              error("failed to find a type argument for Parser: %s", parser);
-              return Optional.absent();
-            }
-            // Equals on TypeMirrors doesn't work - so we compare string 
representations :/
-            return Optional.of(typeUtils.erasure(parsedType).toString());
-          }
-        }));
-    if (configuration != null) {
-      parsersFor = Iterables.concat(parsersFor, Iterables.filter(
-          Iterables.transform(configuration.parserInfo(),
-              new Function<ParserInfo, String>() {
-                @Override @Nullable public String apply(ParserInfo parserInfo) 
{
-                  TypeElement typeElement = 
elementUtils.getTypeElement(parserInfo.parsedType);
-                  // We may not have a type on the classpath for a previous 
round - this is fine as
-                  // long as the no Args in this round that are of the type.
-                  return (typeElement == null)
-                      ? null : 
typeUtils.erasure(typeElement.asType()).toString();
-                }
-              }), Predicates.notNull()));
-    }
-    return ImmutableSet.copyOf(parsersFor);
-  }
-
-  private Iterable<ArgInfo> processAnnotatedArgs(
-      @Nullable final Set<String> parsedTypes,
-      Set<? extends Element> args,
-      final Class<? extends Annotation> argAnnotation) {
-
-    return Optional.presentInstances(Iterables.transform(args,
-        new Function<Element, Optional<ArgInfo>>() {
-          @Override public Optional<ArgInfo> apply(Element arg) {
-            @Nullable TypeElement containingType = processArg(parsedTypes, 
arg, argAnnotation);
-              if (containingType == null) {
-                return Optional.absent();
-              } else {
-                return Optional.of(new ArgInfo(getBinaryName(containingType),
-                    arg.getSimpleName().toString()));
-              }
-            }
-        }));
-  }
-
-  private Set<? extends Element> getAnnotatedElements(RoundEnvironment 
roundEnv,
-      Class<? extends Annotation> argAnnotation) {
-    return roundEnv.getElementsAnnotatedWith(typeElement(argAnnotation));
-  }
-
-  @Nullable
-  private TypeElement processArg(@Nullable Set<String> parsedTypes, Element 
annotationElement,
-      Class<? extends Annotation> annotationType) {
-
-    TypeElement parserType = typeElement(Parser.class);
-    if (annotationElement.getKind() != ElementKind.FIELD) {
-      error("Found a @%s annotation on a non-field %s",
-          annotationType.getSimpleName(), annotationElement);
-      return null;
-    } else {
-      // Only types contain fields so this cast is safe.
-      TypeElement containingType = (TypeElement) 
annotationElement.getEnclosingElement();
-
-      if (!isAssignable(annotationElement.asType(), Arg.class)) {
-        error("Found a @%s annotation on a non-Arg %s.%s",
-            annotationType.getSimpleName(), containingType, annotationElement);
-        return null;
-      }
-      if (!annotationElement.getModifiers().contains(Modifier.STATIC)) {
-        return null;
-      }
-
-      if (parsedTypes != null) {
-        // Check Parser<T> linkage for the Arg<T> type T.
-        TypeMirror typeArgument =
-            getTypeArgument(annotationElement.asType(), 
typeElement(Arg.class));
-        @Nullable AnnotationMirror cmdLine =
-            getAnnotationMirror(annotationElement, 
typeElement(annotationType));
-        if (cmdLine != null) {
-          TypeMirror customParserType = getClassType(cmdLine, "parser", 
parserType).asType();
-          if (typeUtils.isSameType(parserType.asType(), customParserType)) {
-            if (!checkTypePresent(parsedTypes, typeArgument)) {
-              error("No parser registered for %s, %s.%s is un-parseable",
-                  typeArgument, containingType, annotationElement);
-            }
-          } else {
-            TypeMirror customParsedType = getTypeArgument(customParserType, 
parserType);
-            if (!isAssignable(typeArgument, customParsedType)) {
-              error("Custom parser %s parses %s but registered for %s.%s with 
Arg type %s",
-                  customParserType, customParsedType, containingType, 
annotationElement,
-                  typeArgument);
-            }
-          }
-        }
-      }
-
-      // TODO(John Sirois): Add additional compile-time @CmdLine verification 
for:
-      // 1.) for each @CmdLine Arg<T> annotated with @VerifierFor.annotation: 
T is a subtype of
-      //     V where there is a Verifier<V>
-      // 2.) name checks, including dups
-
-      return containingType;
-    }
-  }
-
-  private boolean checkTypePresent(Set<String> types, TypeMirror type) {
-    Iterable<TypeMirror> allTypes = getAllTypes(type);
-    for (TypeMirror t : allTypes) {
-      if (types.contains(typeUtils.erasure(t).toString())) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  private void processParsers(Set<? extends Element> elements) {
-    TypeElement parserType = typeElement(Parser.class);
-    for (Element element : elements) {
-      if (element.getKind() != ElementKind.CLASS) {
-        error("Found an @ArgParser annotation on a non-class %s", element);
-      } else {
-        TypeElement parser = (TypeElement) element;
-        if (!isAssignable(parser, Parser.class)) {
-          error("Found an @ArgParser annotation on a non-Parser %s", element);
-          return;
-        }
-
-        @Nullable String parsedType = getTypeArgument(parser, parserType);
-        if (parsedType != null) {
-          configBuilder.addParser(parsedType, getBinaryName(parser));
-        }
-      }
-    }
-  }
-
-  private void processVerifiers(Set<? extends Element> elements) {
-    TypeElement verifierType = typeElement(Verifier.class);
-    TypeElement verifierForType = typeElement(VerifierFor.class);
-    for (Element element : elements) {
-      if (element.getKind() != ElementKind.CLASS) {
-        error("Found a @VerifierFor annotation on a non-class %s", element);
-      } else {
-        TypeElement verifier = (TypeElement) element;
-        if (!isAssignable(verifier, Verifier.class)) {
-          error("Found a @Verifier annotation on a non-Verifier %s", element);
-          return;
-        }
-
-        @Nullable AnnotationMirror verifierFor = getAnnotationMirror(verifier, 
verifierForType);
-        if (verifierFor != null) {
-          @Nullable TypeElement verifyAnnotationType = 
getClassType(verifierFor, "value", null);
-          if (verifyAnnotationType != null) {
-            @Nullable String verifiedType = getTypeArgument(verifier, 
verifierType);
-            if (verifiedType != null) {
-              String verifyAnnotationClassName =
-                  elementUtils.getBinaryName(verifyAnnotationType).toString();
-              configBuilder.addVerifier(verifiedType, 
verifyAnnotationClassName,
-                  getBinaryName(verifier));
-            }
-          }
-        }
-      }
-    }
-  }
-
-  @Nullable
-  private String getTypeArgument(TypeElement annotatedType, final TypeElement 
baseType) {
-    TypeMirror typeArgument = getTypeArgument(annotatedType.asType(), 
baseType);
-    return typeArgument == null
-        ? null
-        : getBinaryName((TypeElement) typeUtils.asElement(typeArgument));
-  }
-
-  private Iterable<TypeMirror> getAllTypes(TypeMirror type) {
-    return getAllTypes(new HashSet<String>(), 
Lists.<TypeMirror>newArrayList(), type);
-  }
-
-  private Iterable<TypeMirror> getAllTypes(Set<String> visitedTypes, 
List<TypeMirror> types,
-      TypeMirror type) {
-
-    String typeName = typeUtils.erasure(type).toString();
-    if (!visitedTypes.contains(typeName)) {
-      types.add(type);
-      visitedTypes.add(typeName);
-      for (TypeMirror superType : typeUtils.directSupertypes(type)) {
-        getAllTypes(visitedTypes, types, superType);
-      }
-    }
-    return types;
-  }
-
-  @Nullable
-  private TypeMirror getTypeArgument(TypeMirror annotatedType, final 
TypeElement baseType) {
-    for (TypeMirror type : getAllTypes(annotatedType)) {
-      TypeMirror typeArgument = type.accept(new SimpleTypeVisitor6<TypeMirror, 
Void>() {
-        @Override public TypeMirror visitDeclared(DeclaredType t, Void aVoid) {
-          if (isAssignable(t, baseType)) {
-            List<? extends TypeMirror> typeArguments = t.getTypeArguments();
-            if (!typeArguments.isEmpty()) {
-              return typeUtils.erasure(typeArguments.get(0));
-            }
-          }
-          return null;
-        }
-      }, null);
-
-      if (typeArgument != null) {
-        return typeArgument;
-      }
-    }
-    error("Failed to find a type argument for %s in %s", baseType, 
annotatedType);
-    return null;
-  }
-
-  @Nullable
-  private AnnotationMirror getAnnotationMirror(Element element, TypeElement 
annotationType) {
-    for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) {
-      if (typeUtils.isSameType(annotationMirror.getAnnotationType(),  
annotationType.asType())) {
-        return annotationMirror;
-      }
-    }
-    error("Failed to find an annotation of type %s on %s", annotationType, 
element);
-    return null;
-  }
-
-  @SuppressWarnings("unchecked")
-  private TypeElement getClassType(AnnotationMirror annotationMirror, String 
methodName,
-      TypeElement defaultClassType) {
-
-    for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> 
entry
-        : annotationMirror.getElementValues().entrySet()) {
-      if 
(entry.getKey().getSimpleName().equals(elementUtils.getName(methodName))) {
-        TypeElement classType = entry.getValue().accept(
-            new SimpleAnnotationValueVisitor6<TypeElement, Void>() {
-              @Override public TypeElement visitType(TypeMirror t, Void 
unused) {
-                return (TypeElement) processingEnv.getTypeUtils().asElement(t);
-              }
-            }, null);
-
-        if (classType != null) {
-          return classType;
-        }
-      }
-    }
-    if (defaultClassType == null) {
-      error("Could not find a class type for %s.%s", annotationMirror, 
methodName);
-    }
-    return defaultClassType;
-  }
-
-  @Nullable
-  private FileObject createCommandLineDb(Configuration configuration) {
-    String name = isMain ? Configuration.mainResourceName() : 
configuration.nextResourceName();
-    return createResource(Configuration.DEFAULT_RESOURCE_PACKAGE, name);
-  }
-
-  @Nullable
-  private FileObject createResource(String packageName, String name) {
-    try {
-      return 
processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT,
-          packageName, name);
-    } catch (IOException e) {
-      error("Failed to create resource file to store %s/%s: %s",
-          packageName, name, Throwables.getStackTraceAsString(e));
-      return null;
-    }
-  }
-
-  private static final class Resource {
-    private final FileObject resource;
-    private final Writer writer;
-
-    Resource(FileObject resource, Writer writer) {
-      this.resource = resource;
-      this.writer = writer;
-    }
-
-    FileObject getResource() {
-      return resource;
-    }
-
-    Writer getWriter() {
-      return writer;
-    }
-  }
-
-  @Nullable
-  private Resource openCmdLinePropertiesResource(Configuration configuration) {
-    @Nullable FileObject resource = createCommandLineDb(configuration);
-    return openResource(resource);
-  }
-
-  @Nullable
-  private Resource openResource(String packageName, String name) {
-    @Nullable FileObject resource = createResource(packageName, name);
-    return openResource(resource);
-  }
-
-  @Nullable
-  private Resource openResource(@Nullable FileObject resource) {
-    if (resource == null) {
-      return null;
-    }
-    try {
-      log(Kind.NOTE, "Writing %s", resource.toUri());
-      return new Resource(resource, resource.openWriter());
-    } catch (IOException e) {
-      if (!resource.delete()) {
-        log(Kind.WARNING, "Failed to clean up %s after a failing to open it 
for writing",
-            resource.toUri());
-      }
-      error("Failed to open resource file to store %s: %s", resource.toUri(),
-          Throwables.getStackTraceAsString(e));
-      return null;
-    }
-  }
-
-  private TypeElement typeElement(Class<?> type) {
-    return elementUtils.getTypeElement(type.getName());
-  }
-
-  private String getBinaryName(TypeElement typeElement) {
-    return elementUtils.getBinaryName(typeElement).toString();
-  }
-
-  private boolean isAssignable(TypeElement subType, Class<?> baseType) {
-    return isAssignable(subType.asType(), baseType);
-  }
-
-  private boolean isAssignable(TypeMirror subType, Class<?> baseType) {
-    return isAssignable(subType, typeElement(baseType));
-  }
-
-  private boolean isAssignable(TypeMirror subType, TypeElement baseType) {
-    return isAssignable(subType, baseType.asType());
-  }
-
-  private boolean isAssignable(TypeMirror subType, TypeMirror baseType) {
-    return typeUtils.isAssignable(typeUtils.erasure(subType), 
typeUtils.erasure(baseType));
-  }
-
-  private void error(String message, Object ... args) {
-    log(Kind.ERROR, message, args);
-  }
-
-  private void log(Kind kind, String message, Object ... args) {
-    processingEnv.getMessager().printMessage(kind, String.format(message, 
args));
-  }
-}

http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons-args/src/main/java/com/twitter/common/args/apt/Configuration.java
----------------------------------------------------------------------
diff --git 
a/commons-args/src/main/java/com/twitter/common/args/apt/Configuration.java 
b/commons-args/src/main/java/com/twitter/common/args/apt/Configuration.java
deleted file mode 100644
index d19940a..0000000
--- a/commons-args/src/main/java/com/twitter/common/args/apt/Configuration.java
+++ /dev/null
@@ -1,527 +0,0 @@
-/**
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License 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.apt;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintWriter;
-import java.io.Reader;
-import java.io.Writer;
-import java.net.URL;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-import java.util.logging.Logger;
-
-import com.google.common.base.CharMatcher;
-import com.google.common.base.Charsets;
-import com.google.common.base.Function;
-import com.google.common.base.Functions;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Iterators;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import com.google.common.io.CharStreams;
-import com.google.common.io.InputSupplier;
-import com.google.common.io.LineProcessor;
-
-import org.apache.commons.lang.builder.EqualsBuilder;
-import org.apache.commons.lang.builder.HashCodeBuilder;
-import org.apache.commons.lang.builder.ToStringBuilder;
-
-/**
- * Loads and stores {@literal @CmdLine} configuration data. By default, that 
data
- * is contained in text files called cmdline.arg.info.txt.0, 
cmdline.arg.info.txt.1
- * etc. Every time a new Configuration object is created, it consumes all 
existing
- * files with the above names. Saving this Configuration results in creation 
of a
- * file with index increased by one, e.g. cmdline.arg.info.txt.2 in the above
- * example.
- *
- * @author John Sirois
- */
-public final class Configuration {
-
-  /**
-   * Indicates a problem reading stored {@literal @CmdLine} arg configuration 
data.
-   */
-  public static class ConfigurationException extends RuntimeException {
-    public ConfigurationException(String message, Object... args) {
-      super(String.format(message, args));
-    }
-    public ConfigurationException(Throwable cause) {
-      super(cause);
-    }
-  }
-
-  static final String DEFAULT_RESOURCE_PACKAGE = 
Configuration.class.getPackage().getName();
-
-  private static final Logger LOG = 
Logger.getLogger(Configuration.class.getName());
-
-  private static final CharMatcher IDENTIFIER_START =
-      CharMatcher.forPredicate(new Predicate<Character>() {
-        @Override public boolean apply(Character c) {
-          return Character.isJavaIdentifierStart(c);
-        }
-      });
-
-  private static final CharMatcher IDENTIFIER_REST =
-      CharMatcher.forPredicate(new Predicate<Character>() {
-        @Override public boolean apply(Character c) {
-          return Character.isJavaIdentifierPart(c);
-        }
-      });
-
-  private static final Function<URL, InputSupplier<? extends InputStream>> 
URL_TO_INPUT =
-      new Function<URL, InputSupplier<? extends InputStream>>() {
-        @Override public InputSupplier<? extends InputStream> apply(final URL 
resource) {
-          return new InputSupplier<InputStream>() {
-            @Override public InputStream getInput() throws IOException {
-              return resource.openStream();
-            }
-          };
-        }
-      };
-
-  private static final Function<InputSupplier<? extends InputStream>,
-                                InputSupplier<? extends Reader>> 
INPUT_TO_READER =
-      new Function<InputSupplier<? extends InputStream>, InputSupplier<? 
extends Reader>>() {
-        @Override public InputSupplier<? extends Reader> apply(
-            final InputSupplier<? extends InputStream> input) {
-          return CharStreams.newReaderSupplier(input, Charsets.UTF_8);
-        }
-      };
-
-  private static final Function<URL, InputSupplier<? extends Reader>> 
URL_TO_READER =
-      Functions.compose(INPUT_TO_READER, URL_TO_INPUT);
-
-  private static final String DEFAULT_RESOURCE_NAME = "cmdline.arg.info.txt";
-
-  private int nextResourceIndex;
-  private final ImmutableSet<ArgInfo> positionalInfos;
-  private final ImmutableSet<ArgInfo> cmdLineInfos;
-  private final ImmutableSet<ParserInfo> parserInfos;
-  private final ImmutableSet<VerifierInfo> verifierInfos;
-
-  private Configuration(int nextResourceIndex,
-      Iterable<ArgInfo> positionalInfos, Iterable<ArgInfo> cmdLineInfos,
-      Iterable<ParserInfo> parserInfos, Iterable<VerifierInfo> verifierInfos) {
-    this.nextResourceIndex = nextResourceIndex;
-    this.positionalInfos = ImmutableSet.copyOf(positionalInfos);
-    this.cmdLineInfos = ImmutableSet.copyOf(cmdLineInfos);
-    this.parserInfos = ImmutableSet.copyOf(parserInfos);
-    this.verifierInfos = ImmutableSet.copyOf(verifierInfos);
-  }
-
-  private static String checkValidIdentifier(String identifier, boolean 
compound) {
-    Preconditions.checkNotNull(identifier);
-
-    String trimmed = identifier.trim();
-    Preconditions.checkArgument(!trimmed.isEmpty(), "Invalid identifier: 
'%s'", identifier);
-
-    String[] parts = compound ? trimmed.split("\\.") : new String[] {trimmed};
-    for (String part : parts) {
-      Preconditions.checkArgument(
-          IDENTIFIER_REST.matchesAllOf(IDENTIFIER_START.trimLeadingFrom(part)),
-          "Invalid identifier: '%s'", identifier);
-    }
-
-    return trimmed;
-  }
-
-  public static final class ArgInfo {
-    public final String className;
-    public final String fieldName;
-
-    public ArgInfo(String className, String fieldName) {
-      this.className = checkValidIdentifier(className, true);
-      this.fieldName = checkValidIdentifier(fieldName, false);
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-      if (this == obj) {
-        return true;
-      }
-
-      if (!(obj instanceof ArgInfo)) {
-        return false;
-      }
-
-      ArgInfo other = (ArgInfo) obj;
-
-      return new EqualsBuilder()
-          .append(className, other.className)
-          .append(fieldName, other.fieldName)
-          .isEquals();
-    }
-
-    @Override
-    public int hashCode() {
-      return new HashCodeBuilder()
-          .append(className)
-          .append(fieldName)
-          .toHashCode();
-    }
-
-    @Override public String toString() {
-      return new ToStringBuilder(this)
-          .append("className", className)
-          .append("fieldName", fieldName)
-          .toString();
-    }
-  }
-
-  public static final class ParserInfo {
-    public final String parsedType;
-    public final String parserClass;
-
-    public ParserInfo(String parsedType, String parserClass) {
-      this.parsedType = checkValidIdentifier(parsedType, true);
-      this.parserClass = checkValidIdentifier(parserClass, true);
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-      if (this == obj) {
-        return true;
-      }
-
-      if (!(obj instanceof ParserInfo)) {
-        return false;
-      }
-
-      ParserInfo other = (ParserInfo) obj;
-
-      return new EqualsBuilder()
-          .append(parsedType, other.parsedType)
-          .append(parserClass, other.parserClass)
-          .isEquals();
-    }
-
-    @Override
-    public int hashCode() {
-      return new HashCodeBuilder()
-          .append(parsedType)
-          .append(parserClass)
-          .toHashCode();
-    }
-
-    @Override public String toString() {
-      return new ToStringBuilder(this)
-          .append("parsedType", parsedType)
-          .append("parserClass", parserClass)
-          .toString();
-    }
-  }
-
-  public static final class VerifierInfo {
-    public final String verifiedType;
-    public final String verifyingAnnotation;
-    public final String verifierClass;
-
-    public VerifierInfo(String verifiedType, String verifyingAnnotation, 
String verifierClass) {
-      this.verifiedType = checkValidIdentifier(verifiedType, true);
-      this.verifyingAnnotation = checkValidIdentifier(verifyingAnnotation, 
true);
-      this.verifierClass = checkValidIdentifier(verifierClass, true);
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-      if (this == obj) {
-        return true;
-      }
-
-      if (!(obj instanceof VerifierInfo)) {
-        return false;
-      }
-
-      VerifierInfo other = (VerifierInfo) obj;
-
-      return new EqualsBuilder()
-          .append(verifiedType, other.verifiedType)
-          .append(verifyingAnnotation, other.verifyingAnnotation)
-          .append(verifierClass, other.verifierClass)
-          .isEquals();
-    }
-
-    @Override
-    public int hashCode() {
-      return new HashCodeBuilder()
-          .append(verifiedType)
-          .append(verifyingAnnotation)
-          .append(verifierClass)
-          .toHashCode();
-    }
-
-    @Override public String toString() {
-      return new ToStringBuilder(this)
-          .append("verifiedType", verifiedType)
-          .append("verifyingAnnotation", verifyingAnnotation)
-          .append("verifierClass", verifierClass)
-          .toString();
-    }
-  }
-
-  static class Builder {
-    private final Set<ArgInfo> positionalInfos = Sets.newHashSet();
-    private final Set<ArgInfo> argInfos = Sets.newHashSet();
-    private final Set<ParserInfo> parserInfos = Sets.newHashSet();
-    private final Set<VerifierInfo> verifierInfos = Sets.newHashSet();
-
-    public boolean isEmpty() {
-      return positionalInfos.isEmpty()
-          && argInfos.isEmpty()
-          && parserInfos.isEmpty()
-          && verifierInfos.isEmpty();
-    }
-
-    void addPositionalInfo(ArgInfo positionalInfo) {
-      positionalInfos.add(positionalInfo);
-    }
-
-    void addCmdLineArg(ArgInfo argInfo) {
-      argInfos.add(argInfo);
-    }
-
-    void addParser(ParserInfo parserInfo) {
-      parserInfos.add(parserInfo);
-    }
-
-    public void addParser(String parserForType, String parserType) {
-      addParser(new ParserInfo(parserForType, parserType));
-    }
-
-    void addVerifier(VerifierInfo verifierInfo) {
-      verifierInfos.add(verifierInfo);
-    }
-
-    public void addVerifier(String verifierForType, String annotationType, 
String verifierType) {
-      addVerifier(new VerifierInfo(verifierForType, annotationType, 
verifierType));
-    }
-
-    public Configuration build(Configuration configuration) {
-      return new Configuration(configuration.nextResourceIndex + 1,
-          positionalInfos, argInfos, parserInfos, verifierInfos);
-    }
-  }
-
-  private static String getResourceName(int index) {
-    return String.format("%s.%s", DEFAULT_RESOURCE_NAME, index);
-  }
-
-  private static String getResourcePath(int index) {
-    return String.format("%s/%s", DEFAULT_RESOURCE_PACKAGE.replace('.', '/'),
-        getResourceName(index));
-  }
-
-  static final class ConfigurationResources {
-    private final int nextResourceIndex;
-    private final Iterator<URL> resources;
-
-    private ConfigurationResources(int nextResourceIndex, Iterator<URL> 
resources) {
-      this.nextResourceIndex = nextResourceIndex;
-      this.resources = resources;
-    }
-  }
-
-  /**
-   * Loads the {@literal @CmdLine} argument configuration data stored in the 
classpath.
-   *
-   * @return The {@literal @CmdLine} argument configuration materialized from 
the classpath.
-   * @throws ConfigurationException if any configuration data is malformed.
-   * @throws IOException if the configuration data can not be read from the 
classpath.
-   */
-  public static Configuration load() throws ConfigurationException, 
IOException {
-    ConfigurationResources allResources = getAllResources();
-    List<URL> configs = ImmutableList.copyOf(allResources.resources);
-    if (configs.isEmpty()) {
-      LOG.info("No @CmdLine arg configs found on the classpath");
-    } else {
-      LOG.info("Loading @CmdLine config from: " + configs);
-    }
-    return load(allResources.nextResourceIndex, configs);
-  }
-
-  private static ConfigurationResources getAllResources() throws IOException {
-    int maxResourceIndex = 0;
-    Iterator<URL> allResources = getResources(0); // Try for a main
-    // Probe for resource files with index up to 10 (or more, while resources 
at the
-    // given index can be found)
-    for (int nextResourceIndex = 1; nextResourceIndex <= maxResourceIndex + 10;
-         nextResourceIndex++) {
-      Iterator<URL> resources = getResources(nextResourceIndex);
-      if (resources.hasNext()) {
-        allResources = Iterators.concat(allResources, resources);
-        maxResourceIndex = nextResourceIndex;
-      }
-    }
-    return new ConfigurationResources(maxResourceIndex + 1, allResources);
-  }
-
-  private static Iterator<URL> getResources(int index) throws IOException {
-    return Iterators.forEnumeration(
-        
Configuration.class.getClassLoader().getResources(getResourcePath(index)));
-  }
-
-  private static final class ConfigurationParser implements 
LineProcessor<Configuration> {
-    private final int nextIndex;
-    private int lineNumber = 0;
-
-    private final ImmutableList.Builder<ArgInfo> positionalInfo = 
ImmutableList.builder();
-    private final ImmutableList.Builder<ArgInfo> fieldInfoBuilder = 
ImmutableList.builder();
-    private final ImmutableList.Builder<ParserInfo> parserInfoBuilder = 
ImmutableList.builder();
-    private final ImmutableList.Builder<VerifierInfo> verifierInfoBuilder = 
ImmutableList.builder();
-
-    private ConfigurationParser(int nextIndex) {
-      this.nextIndex = nextIndex;
-    }
-
-    @Override
-    public boolean processLine(String line) throws IOException {
-      ++lineNumber;
-      String trimmed = line.trim();
-      if (!trimmed.isEmpty() && !trimmed.startsWith("#")) {
-        List<String> parts = Lists.newArrayList(trimmed.split(" "));
-        if (parts.size() < 1) {
-          throw new ConfigurationException("Invalid line: %s @%d", trimmed, 
lineNumber);
-        }
-
-        String type = parts.remove(0);
-        if ("positional".equals(type)) {
-          if (parts.size() != 2) {
-            throw new ConfigurationException(
-                "Invalid positional line: %s @%d", trimmed, lineNumber);
-          }
-          positionalInfo.add(new ArgInfo(parts.get(0), parts.get(1)));
-        } else if ("field".equals(type)) {
-          if (parts.size() != 2) {
-            throw new ConfigurationException("Invalid field line: %s @%d", 
trimmed, lineNumber);
-          }
-          fieldInfoBuilder.add(new ArgInfo(parts.get(0), parts.get(1)));
-        } else if ("parser".equals(type)) {
-          if (parts.size() != 2) {
-            throw new ConfigurationException("Invalid parser line: %s @%d", 
trimmed, lineNumber);
-          }
-          parserInfoBuilder.add(new ParserInfo(parts.get(0), parts.get(1)));
-        } else if ("verifier".equals(type)) {
-          if (parts.size() != 3) {
-            throw new ConfigurationException("Invalid verifier line: %s @%d", 
trimmed, lineNumber);
-          }
-          verifierInfoBuilder.add(new VerifierInfo(parts.get(0), parts.get(1), 
parts.get(2)));
-        } else {
-          LOG.warning(String.format("Did not recognize entry type %s for line: 
%s @%d",
-              type, trimmed, lineNumber));
-        }
-      }
-      return true;
-    }
-
-    @Override
-    public Configuration getResult() {
-      return new Configuration(nextIndex, positionalInfo.build(),
-          fieldInfoBuilder.build(), parserInfoBuilder.build(), 
verifierInfoBuilder.build());
-    }
-  }
-
-  private static Configuration load(int nextIndex, List<URL> configs)
-      throws ConfigurationException, IOException {
-    InputSupplier<Reader> input = 
CharStreams.join(Iterables.transform(configs, URL_TO_READER));
-    return CharStreams.readLines(input, new ConfigurationParser(nextIndex));
-  }
-
-  public boolean isEmpty() {
-    return positionalInfos.isEmpty()
-        && cmdLineInfos.isEmpty()
-        && parserInfos.isEmpty()
-        && verifierInfos.isEmpty();
-  }
-
-  /**
-   * Returns the field info for the sole {@literal @Positional} annotated 
field on the classpath,
-   * if any.
-   *
-   * @return The field info for the {@literal @Positional} annotated field if 
any.
-   */
-  public Iterable<ArgInfo> positionalInfo() {
-    return positionalInfos;
-  }
-
-  /**
-   * Returns the field info for all the {@literal @CmdLine} annotated fields 
on the classpath.
-   *
-   * @return The field info for all the {@literal @CmdLine} annotated fields.
-   */
-  public Iterable<ArgInfo> optionInfo() {
-    return cmdLineInfos;
-  }
-
-  /**
-   * Returns the parser info for all the {@literal @ArgParser} annotated 
parsers on the classpath.
-   *
-   * @return The parser info for all the {@literal @ArgParser} annotated 
parsers.
-   */
-  public Iterable<ParserInfo> parserInfo() {
-    return parserInfos;
-  }
-
-  /**
-   * Returns the verifier info for all the {@literal @VerifierFor} annotated 
verifiers on the
-   * classpath.
-   *
-   * @return The verifier info for all the {@literal @VerifierFor} annotated 
verifiers.
-   */
-  public Iterable<VerifierInfo> verifierInfo() {
-    return verifierInfos;
-  }
-
-  static String mainResourceName() {
-    return getResourceName(0);
-  }
-
-  String nextResourceName() {
-    return getResourceName(nextResourceIndex);
-  }
-
-  void store(Writer output, String message) {
-    PrintWriter writer = new PrintWriter(output);
-    writer.printf("# %s\n", new Date());
-    writer.printf("# %s\n ", message);
-
-    writer.println();
-    for (ArgInfo info : positionalInfos) {
-      writer.printf("positional %s %s\n", info.className, info.fieldName);
-    }
-
-    writer.println();
-    for (ArgInfo info : cmdLineInfos) {
-      writer.printf("field %s %s\n", info.className, info.fieldName);
-    }
-
-    writer.println();
-    for (ParserInfo info : parserInfos) {
-      writer.printf("parser %s %s\n", info.parsedType, info.parserClass);
-    }
-
-    writer.println();
-    for (VerifierInfo info : verifierInfos) {
-      writer.printf("verifier %s %s %s\n",
-          info.verifiedType, info.verifyingAnnotation, info.verifierClass);
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons-args/src/main/java/org/apache/aurora/common/args/Arg.java
----------------------------------------------------------------------
diff --git a/commons-args/src/main/java/org/apache/aurora/common/args/Arg.java 
b/commons-args/src/main/java/org/apache/aurora/common/args/Arg.java
new file mode 100644
index 0000000..8e915c6
--- /dev/null
+++ b/commons-args/src/main/java/org/apache/aurora/common/args/Arg.java
@@ -0,0 +1,126 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License 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 org.apache.aurora.common.args;
+
+import javax.annotation.Nullable;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+
+/**
+ * Wrapper class for the value of an argument.  For proper behavior, an {@code 
Arg} should always
+ * be annotated with {@link CmdLine}, which will define the command line 
interface to the argument.
+ */
+public class Arg<T> {
+
+  @Nullable private final T defaultValue;
+  @Nullable private T value;
+  private boolean hasDefault = true;
+  private boolean valueApplied = false;
+  private boolean valueObserved = false;
+
+  /**
+   * Creates an arg that has no default value, meaning that its value can only 
ever be retrieved
+   * if it has been externally set.
+   */
+  public Arg() {
+    this(null);
+    hasDefault = false;
+  }
+
+  /**
+   * Creates an arg that has a default value, and may optionally be set.
+   *
+   * @param defaultValue The default value for the arg.
+   */
+  public Arg(@Nullable T defaultValue) {
+    this.defaultValue = defaultValue;
+    value = defaultValue;
+  }
+
+  synchronized void set(@Nullable T appliedValue) {
+    Preconditions.checkState(!valueApplied, "A value cannot be applied twice 
to an argument.");
+    Preconditions.checkState(!valueObserved, "A value cannot be changed after 
it was read.");
+    valueApplied = true;
+    value = appliedValue;
+  }
+
+  @VisibleForTesting
+  synchronized void reset() {
+    valueApplied = false;
+    valueObserved = false;
+    value = hasDefault ? defaultValue : null;
+  }
+
+  public boolean hasDefault() {
+    return hasDefault;
+  }
+
+  /**
+   * Gets the value of the argument.  If a value has not yet been applied to 
the argument, or the
+   * argument did not provide a default value, {@link IllegalStateException} 
will be thrown.
+   *
+   * @return The argument value.
+   */
+  @Nullable
+  public synchronized T get() {
+    // TODO(William Farner): This has a tendency to break bad-arg reporting by 
ArgScanner.  Fix.
+    Preconditions.checkState(valueApplied || hasDefault,
+        "A value may only be retrieved from a variable that has a default or 
has been set.");
+    valueObserved = true;
+    return uncheckedGet();
+  }
+
+  /**
+   * Checks whether a value has been applied to the argument (i.e., apart from 
the default).
+   *
+   * @return {@code true} if a value from the command line has been applied to 
this arg,
+   *         {@code false} otherwise.
+   */
+  public synchronized boolean hasAppliedValue() {
+    return valueApplied;
+  }
+
+  /**
+   * Gets the value of the argument, without checking whether a default was 
available or if a
+   * value was applied.
+   *
+   * @return The argument value.
+   */
+  @Nullable
+  synchronized T uncheckedGet() {
+    return value;
+  }
+
+  /**
+   * Convenience factory method to create an arg that has no default value.
+   *
+   * @param <T> Type of arg value.
+   * @return A new arg.
+   */
+  public static <T> Arg<T> create() {
+    return new Arg<T>();
+  }
+
+  /**
+   * Convenience factory method to create an arg with a default value.
+   *
+   * @param value Default argument value.
+   * @param <T> Type of arg value.
+   * @return A new arg.
+   */
+  public static <T> Arg<T> create(@Nullable T value) {
+    return new Arg<T>(value);
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons-args/src/main/java/org/apache/aurora/common/args/ArgParser.java
----------------------------------------------------------------------
diff --git 
a/commons-args/src/main/java/org/apache/aurora/common/args/ArgParser.java 
b/commons-args/src/main/java/org/apache/aurora/common/args/ArgParser.java
new file mode 100644
index 0000000..25ed250
--- /dev/null
+++ b/commons-args/src/main/java/org/apache/aurora/common/args/ArgParser.java
@@ -0,0 +1,28 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License 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 org.apache.aurora.common.args;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Annotation to register a command line argument parser globally.
+ */
+@Target(TYPE)
+@Retention(SOURCE)
+public @interface ArgParser {
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons-args/src/main/java/org/apache/aurora/common/args/CmdLine.java
----------------------------------------------------------------------
diff --git 
a/commons-args/src/main/java/org/apache/aurora/common/args/CmdLine.java 
b/commons-args/src/main/java/org/apache/aurora/common/args/CmdLine.java
new file mode 100644
index 0000000..a72ea7a
--- /dev/null
+++ b/commons-args/src/main/java/org/apache/aurora/common/args/CmdLine.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License 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 org.apache.aurora.common.args;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Annotation for a command line argument.
+ */
+@Target(FIELD)
+@Retention(RUNTIME)
+public @interface CmdLine {
+  /**
+   * The short name of the argument, as supplied on the command line.  The 
argument can also be
+   * accessed by the canonical name, which is {@code 
com.foo.bar.MyArgClass.arg_name}.
+   * If the global scope contains more than one argument with the same name, 
all colliding arguments
+   * must be disambiguated with the canonical form.
+   *
+   * The argument name must match the format {@code [\w\-\.]+}.
+   */
+  String name();
+
+  /**
+   * The help string to display on the command line in a usage message.
+   */
+  String help();
+
+  /**
+   * The parser class to use for parsing this argument.  The parser must 
return the same type as
+   * the field being annotated.
+   */
+  Class<? extends Parser<?>> parser() default NoParser.class;
+
+  /**
+   * The flag to indicate whether an argument file is accepted for this 
argument.
+   *
+   */
+  boolean argFile() default false;
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons-args/src/main/java/org/apache/aurora/common/args/NoParser.java
----------------------------------------------------------------------
diff --git 
a/commons-args/src/main/java/org/apache/aurora/common/args/NoParser.java 
b/commons-args/src/main/java/org/apache/aurora/common/args/NoParser.java
new file mode 100644
index 0000000..3366531
--- /dev/null
+++ b/commons-args/src/main/java/org/apache/aurora/common/args/NoParser.java
@@ -0,0 +1,23 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License 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 org.apache.aurora.common.args;
+
+/**
+ * A sentinel parser type for internal use indicating no parser has been 
selected yet.
+ */
+abstract class NoParser implements Parser<Object> {
+  private NoParser() {
+    throw new UnsupportedOperationException("Not intended for construction.");
+  }
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons-args/src/main/java/org/apache/aurora/common/args/Parser.java
----------------------------------------------------------------------
diff --git 
a/commons-args/src/main/java/org/apache/aurora/common/args/Parser.java 
b/commons-args/src/main/java/org/apache/aurora/common/args/Parser.java
new file mode 100644
index 0000000..93c2323
--- /dev/null
+++ b/commons-args/src/main/java/org/apache/aurora/common/args/Parser.java
@@ -0,0 +1,35 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License 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 org.apache.aurora.common.args;
+
+import java.lang.reflect.Type;
+
+/**
+ * An interface to a command line argument parser.
+ *
+ * @param <T> The base class this parser can parse all subtypes of.
+ */
+public interface Parser<T> {
+  /**
+   * Parses strings as arguments of a given subtype of {@code T}.
+   *
+   * @param parserOracle The registered parserOracle for delegation.
+   * @param type The target type of the parsed argument.
+   * @param raw The raw value of the argument.
+   * @return A value of the given type parsed from the raw value.
+   * @throws IllegalArgumentException if the raw value could not be parsed 
into a value of the
+   *     given type.
+   */
+  T parse(ParserOracle parserOracle, Type type, String raw) throws 
IllegalArgumentException;
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons-args/src/main/java/org/apache/aurora/common/args/ParserOracle.java
----------------------------------------------------------------------
diff --git 
a/commons-args/src/main/java/org/apache/aurora/common/args/ParserOracle.java 
b/commons-args/src/main/java/org/apache/aurora/common/args/ParserOracle.java
new file mode 100644
index 0000000..e84d302
--- /dev/null
+++ b/commons-args/src/main/java/org/apache/aurora/common/args/ParserOracle.java
@@ -0,0 +1,31 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License 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 org.apache.aurora.common.args;
+
+import com.google.common.reflect.TypeToken;
+
+/**
+ * A registry of Parsers for different supported argument types.
+ */
+public interface ParserOracle {
+
+  /**
+   * Gets the parser associated with a class.
+   *
+   * @param type Type to get the parser for.
+   * @return The parser for {@code cls}.
+   * @throws IllegalArgumentException If no parser was found for {@code cls}.
+   */
+  <T> Parser<T> get(TypeToken<T> type) throws IllegalArgumentException;
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons-args/src/main/java/org/apache/aurora/common/args/Positional.java
----------------------------------------------------------------------
diff --git 
a/commons-args/src/main/java/org/apache/aurora/common/args/Positional.java 
b/commons-args/src/main/java/org/apache/aurora/common/args/Positional.java
new file mode 100644
index 0000000..1c6f86f
--- /dev/null
+++ b/commons-args/src/main/java/org/apache/aurora/common/args/Positional.java
@@ -0,0 +1,40 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License 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 org.apache.aurora.common.args;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Annotation to mark an {@link Arg} for gathering the positional command line 
arguments.
+ */
+@Retention(RUNTIME)
+@Target(FIELD)
+public @interface Positional {
+  /**
+   * The help string to display on the command line in a usage message.
+   */
+  String help();
+
+  /**
+   * The parser class to use for parsing the positional arguments.  The parser 
must return the same
+   * type as the field being annotated.
+   */
+  Class<? extends Parser<?>> parser() default NoParser.class;
+
+  // TODO: https://github.com/twitter/commons/issues/353, Consider to add 
argFile for positional.
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons-args/src/main/java/org/apache/aurora/common/args/Verifier.java
----------------------------------------------------------------------
diff --git 
a/commons-args/src/main/java/org/apache/aurora/common/args/Verifier.java 
b/commons-args/src/main/java/org/apache/aurora/common/args/Verifier.java
new file mode 100644
index 0000000..8f09a98
--- /dev/null
+++ b/commons-args/src/main/java/org/apache/aurora/common/args/Verifier.java
@@ -0,0 +1,37 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License 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 org.apache.aurora.common.args;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * Typedef for a constraint verifier.
+ */
+public interface Verifier<T> {
+  /**
+   * Verifies the value against the annotation.
+   *
+   * @param value Value that is being applied.
+   * @throws IllegalArgumentException if the value is invalid.
+   */
+  void verify(T value, Annotation annotation) throws IllegalArgumentException;
+
+  /**
+   * Returns a representation of the constraint this verifier checks.
+   *
+   * @param argType The type of the {@link Arg} this annotation applies to.
+   * @return A representation of the constraint this verifier checks.
+   */
+  String toString(Class<? extends T> argType, Annotation annotation);
+}

http://git-wip-us.apache.org/repos/asf/aurora/blob/06ddaadb/commons-args/src/main/java/org/apache/aurora/common/args/VerifierFor.java
----------------------------------------------------------------------
diff --git 
a/commons-args/src/main/java/org/apache/aurora/common/args/VerifierFor.java 
b/commons-args/src/main/java/org/apache/aurora/common/args/VerifierFor.java
new file mode 100644
index 0000000..aad8807
--- /dev/null
+++ b/commons-args/src/main/java/org/apache/aurora/common/args/VerifierFor.java
@@ -0,0 +1,34 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License 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 org.apache.aurora.common.args;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * Annotation to register a command line argument verifier.
+ */
+@Target(TYPE)
+@Retention(SOURCE)
+public @interface VerifierFor {
+  /**
+   * Returns the annotation that marks a field for verification by the 
annotated
+   * {@link Verifier} class.
+   */
+  Class<? extends Annotation> value();
+}

Reply via email to