First steps toward new parameter parsing
diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java
new file mode 100644
index 0000000..954bfc0
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/JCommander.java
@@ -0,0 +1,150 @@
+package com.beust.jcommander;
+
+import org.testng.collections.Lists;
+import org.testng.collections.Maps;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.util.List;
+import java.util.Map;
+
+public class JCommander {
+  private Map<String, ParameterDescription> m_descriptions;
+  private Object m_object;
+
+  public JCommander(Object object) {
+    m_object = object;
+  }
+
+  public JCommander(Object object, String[] args) {
+    m_object = object;
+    parse(args);
+  }
+
+  public void parse(String[] args) {
+    createDescriptions();
+    parseValues(expandArgs(args));
+  }
+
+  /**
+   * Expand the command line parameters to take @ parameters into account.
+   * When @ is encountered, the content of the file that follows is inserted
+   * in the command line
+   * @param originalArgv the original command line parameters
+   * @return the new and enriched command line parameters
+   */
+  private static String[] expandArgs(String[] originalArgv) {
+    List<String> vResult = Lists.newArrayList();
+    
+    for (String arg : originalArgv) {
+
+      if (arg.startsWith("@")) {
+        String fileName = arg.substring(1);
+        vResult.addAll(readFile(fileName));
+      }
+      else {
+        vResult.add(arg);
+      }
+    }
+    
+    return vResult.toArray(new String[vResult.size()]);
+  }
+
+  /**
+   * Reads the file specified by filename and returns the file content as a string.
+   * End of lines are replaced by a space
+   * 
+   * @param fileName the command line filename
+   * @return the file content as a string.
+   */
+  public static List<String> readFile(String fileName) {
+    List<String> result = Lists.newArrayList();
+
+    try {
+      BufferedReader bufRead = new BufferedReader(new FileReader(fileName));
+
+      String line;
+
+      // Read through file one line at time. Print line # and line
+      while ((line = bufRead.readLine()) != null) {
+        result.add(line);
+      }
+
+      bufRead.close();
+    }
+    catch (IOException e) {
+      throw new ParameterException("Could not read file " + fileName + ": " + e);
+    }
+
+    return result;
+  }
+
+  /**
+   * @param string
+   * @return
+   */
+  private static String trim(String string) {
+    String result = string.trim();
+    if (result.startsWith("\"")) {
+      if (result.endsWith("\"")) {
+          return result.substring(1, result.length() - 1);
+      } else {
+          return result.substring(1);
+      }
+    } else {
+      return result;
+    }
+  }
+
+  private void createDescriptions() {
+    m_descriptions = Maps.newHashMap();
+    Class<?> cls = m_object.getClass();
+    for (Field f : cls.getDeclaredFields()) {
+      p("Field:" + f.getName());
+      f.setAccessible(true);
+      Annotation annotation = f.getAnnotation(Parameter.class);
+      if (annotation != null) {
+        Parameter p = (Parameter) annotation;
+        p("Adding description for " + p.name());
+        ParameterDescription pd = new ParameterDescription(m_object, p, f);
+        m_descriptions.put(p.name(), pd);
+      }
+    }
+  }
+
+  private void p(String string) {
+    System.out.println("[JCommander] " + string);
+  }
+
+  private void parseValues(String[] args) {
+    for (int i = 0; i < args.length; i++) {
+      String a = trim(args[i]);
+      if (a.startsWith("-")) {
+        ParameterDescription pd = m_descriptions.get(a);
+        if (pd != null) {
+          Class<?> fieldType = pd.getField().getType();
+          if (fieldType == boolean.class || fieldType == Boolean.class) {
+            pd.addValue(Boolean.TRUE);
+          } else if (i + 1 < args.length) {
+            pd.addValue(args[i + 1]);
+          } else {
+            throw new ParameterException("Parameter expected after " + args[i]);
+          }
+          i++;
+        } else {
+          throw new ParameterException("Unknown option: " + a);
+        }
+      }
+    }
+  }
+
+  public void usage() {
+    System.out.println("Usage:");
+    for (ParameterDescription pd : m_descriptions.values()) {
+      System.out.println("\t" + pd.getName() + "\t" + pd.getDescription());
+    }
+  }
+}
diff --git a/src/main/java/com/beust/jcommander/Parameter.java b/src/main/java/com/beust/jcommander/Parameter.java
new file mode 100644
index 0000000..a30d3b0
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/Parameter.java
@@ -0,0 +1,15 @@
+package com.beust.jcommander;
+
+import static java.lang.annotation.ElementType.FIELD;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
+@Target({ FIELD })
+public @interface Parameter {
+
+  String name() default "";
+
+  String description() default "";
+}
diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java
new file mode 100644
index 0000000..cdc7579
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/ParameterDescription.java
@@ -0,0 +1,69 @@
+package com.beust.jcommander;
+
+import org.testng.collections.Lists;
+
+import java.lang.reflect.Field;
+import java.util.List;
+import java.util.Set;
+
+public class ParameterDescription {
+  private Object m_object;
+  private Parameter m_parameterAnnotation;
+  private Field m_field;
+  /** Keep track of whether a value was added to flag an error */
+  private boolean m_added = false;
+
+  public ParameterDescription(Object object, Parameter annotation, Field field) {
+    m_object = object;
+    m_parameterAnnotation = annotation;
+    m_field = field;
+  }
+
+  public String getName() {
+    return m_parameterAnnotation.name();
+  }
+
+  public String getDescription() {
+    return m_parameterAnnotation.description();
+  }
+
+  public Field getField() {
+    return m_field;
+  }
+
+  private boolean isMultiOption() {
+    Class<?> fieldType = m_field.getType();
+    return fieldType.equals(List.class) || fieldType.equals(Set.class);
+  }
+
+  public void addValue(Object value) {
+    if (m_added && ! isMultiOption()) {
+      throw new ParameterException("Can only specify option " + getName() + " once.");
+    }
+
+    m_added = true;
+    try {
+      Class<?> fieldType = m_field.getType();
+      if (fieldType.equals(String.class)) {
+        m_field.set(m_object, value);
+      } else if (fieldType.equals(int.class) || fieldType.equals(Integer.class)) {
+        m_field.set(m_object, Integer.parseInt(value.toString()));
+      } else if (fieldType.equals(long.class) || fieldType.equals(Long.class)) {
+        m_field.set(m_object, Long.parseLong(value.toString()));
+      } else if (fieldType.equals(float.class) || fieldType.equals(Float.class)) {
+        m_field.set(m_object, Float.parseFloat(value.toString()));
+      } else if (isMultiOption()) {
+        List l = (List) m_field.get(m_object);
+        if (l == null) {
+          l = Lists.newArrayList();
+          m_field.set(m_object, l);
+        }
+        l.add(value);
+      }
+    } catch (IllegalArgumentException e) {
+      e.printStackTrace();
+    } catch (IllegalAccessException e) {
+      e.printStackTrace();
+    }
+  }
+}
diff --git a/src/main/java/com/beust/jcommander/ParameterException.java b/src/main/java/com/beust/jcommander/ParameterException.java
new file mode 100644
index 0000000..5004cd0
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/ParameterException.java
@@ -0,0 +1,9 @@
+package com.beust.jcommander;
+
+public class ParameterException extends RuntimeException {
+
+  public ParameterException(String string) {
+    super(string);
+  }
+
+}
diff --git a/src/main/java/org/testng/CommandLineArgs.java b/src/main/java/org/testng/CommandLineArgs.java
new file mode 100644
index 0000000..9a4f826
--- /dev/null
+++ b/src/main/java/org/testng/CommandLineArgs.java
@@ -0,0 +1,87 @@
+package org.testng;
+
+import com.beust.jcommander.Parameter;
+
+public class CommandLineArgs {
+
+  @Parameter(name = "-port", description = "The port")
+  private Integer m_port;
+
+  @Parameter(name = "-host", description = "The host")
+  private String m_host;
+
+  @Parameter(name = "-master", description ="Master mode")
+  private Boolean m_master;
+
+  @Parameter(name = "-slave", description ="Slave mode")
+  private Boolean m_slave;
+
+  @Parameter(name = "-groups", description = "Comma-separated list of group names to be run")
+  private String m_groups;
+
+  @Parameter(name = "-excludedgroups", description ="Comma-separated list of group names to be run")
+  private String m_excludedGroups;
+  
+  @Parameter(name = "-d", description ="Output directory")
+  private String m_outputDirectory;
+  
+  @Parameter(name = "-junit", description ="JUnit mode")
+  private Boolean m_junit;
+
+  @Parameter(name = "-listener", description = "List of .class files or list of class names" +
+      " implementing ITestListener or ISuiteListener")
+  private String m_listener;
+
+  @Parameter(name = "-methodselectors", description = "List of .class files or list of class " +
+  		"names implementing IMethodSelector")
+  private String m_methodSelectors;
+
+  @Parameter(name = "-objectfactory", description = "List of .class files or list of class names " +
+      "implementing ITestRunnerFactory")
+  private String m_objectFactory;
+
+  @Parameter(name = "-parallel", description = "Parallel mode (methods, tests or classes)")
+  private String m_parallelMode;
+
+  @Parameter(name = "-threadcount", description = "Number of threads to use when running tests " +
+      "in parallel")
+  private Integer m_threadCount;
+
+  @Parameter(name = "-dataproviderthreadcount", description = "Number of threads to use when " +
+      "running tests in parallel")
+  private Integer m_dataProviderThreadCount;
+
+  @Parameter(name = "-suitename", description = "Default name of test suite, if not specified " +
+      "in suite definition file or source code")
+  private String m_suiteName;
+
+  @Parameter(name = "-testname", description = "Default name of test, if not specified in suite" +
+      "definition file or source code")
+  private String m_testName;
+
+  @Parameter(name = "-reporter", description = "Extended configuration for custom report listener")
+  private String m_reporter;
+
+  /**
+   * Used as map key for the complete list of report listeners provided with the above argument
+   */
+  @Parameter(name = "-reporterslist")
+  private String m_reportersList;
+
+  @Parameter(name = "-skipfailedinvocationcounts")
+  private Boolean m_skipFailedInvocationCounts;
+
+  @Parameter(name = "-testclass", description = "The list of test classes")
+  private String m_testClass;
+
+  @Parameter(name = "-testnames", description = "The list of test names to run")
+  private String m_testNames;
+
+  @Parameter(name = "-testjar", description = "")
+  private String m_testJar;
+
+  @Parameter(name = "-testRunFactory", description = "")
+  private String m_testRunFactory;
+
+  public static final String DATA_PROVIDER_THREAD_COUNT = "-dataproviderthreadcount";
+}