/** Factory method to build up an {@code ExecutionCommand} based on supplied parameters. */
    public static ExecutionCommand parseArgs(String[] args) {
      Option tableOption =
          new Option(
              "t",
              "table",
              true,
              "Overrides the table into which the CSV data is loaded and is case sensitive");
      Option headerOption =
          new Option(
              "h",
              "header",
              true,
              "Overrides the column names to"
                  + " which the CSV data maps and is case sensitive. A special value of "
                  + "in-line indicating that the first line of the CSV file determines the "
                  + "column to which the data maps");
      Option strictOption =
          new Option(
              "s",
              "strict",
              false,
              "Use strict mode by throwing "
                  + "an exception if a column name doesn't match during CSV loading");
      Option delimiterOption =
          new Option(
              "d",
              "delimiter",
              true,
              "Field delimiter for CSV loader. A digit is interpreted as "
                  + "1 -> ctrl A, 2 -> ctrl B ... 9 -> ctrl I.");
      Option quoteCharacterOption =
          new Option(
              "q",
              "quote-character",
              true,
              "Quote character for CSV loader. A digit is interpreted as a control " + "character");
      Option escapeCharacterOption =
          new Option(
              "e",
              "escape-character",
              true,
              "Escape character for CSV loader. A digit is interpreted as a control "
                  + "character");
      Option arrayValueSeparatorOption =
          new Option(
              "a", "array-separator", true, "Define the array element separator, defaults to ':'");
      Options options = new Options();
      options.addOption(tableOption);
      options.addOption(headerOption);
      options.addOption(strictOption);
      options.addOption(delimiterOption);
      options.addOption(quoteCharacterOption);
      options.addOption(escapeCharacterOption);
      options.addOption(arrayValueSeparatorOption);

      CommandLineParser parser = new PosixParser();
      CommandLine cmdLine = null;
      try {
        cmdLine = parser.parse(options, args);
      } catch (ParseException e) {
        usageError(options);
      }

      ExecutionCommand execCmd = new ExecutionCommand();

      if (cmdLine.hasOption(tableOption.getOpt())) {
        execCmd.tableName = cmdLine.getOptionValue(tableOption.getOpt());
      }

      if (cmdLine.hasOption(headerOption.getOpt())) {
        String columnString = cmdLine.getOptionValue(headerOption.getOpt());
        if (HEADER_IN_LINE.equals(columnString)) {
          execCmd.columns = ImmutableList.of();
        } else {
          execCmd.columns =
              ImmutableList.copyOf(Splitter.on(",").trimResults().split(columnString));
        }
      }

      execCmd.strict = cmdLine.hasOption(strictOption.getOpt());
      execCmd.fieldDelimiter = getCharacter(cmdLine.getOptionValue(delimiterOption.getOpt(), ","));
      execCmd.quoteCharacter =
          getCharacter(cmdLine.getOptionValue(quoteCharacterOption.getOpt(), "\""));

      if (cmdLine.hasOption(escapeCharacterOption.getOpt())) {
        execCmd.escapeCharacter =
            getCharacter(cmdLine.getOptionValue(escapeCharacterOption.getOpt(), "\\"));
      }

      execCmd.arrayElementSeparator =
          cmdLine.getOptionValue(
              arrayValueSeparatorOption.getOpt(), CSVCommonsLoader.DEFAULT_ARRAY_ELEMENT_SEPARATOR);

      List<String> argList = Lists.newArrayList(cmdLine.getArgList());
      if (argList.isEmpty()) {
        usageError("Connection string to HBase must be supplied", options);
      }
      execCmd.connectionString = argList.remove(0);
      List<String> inputFiles = Lists.newArrayList();
      for (String arg : argList) {
        if (arg.endsWith(CSV_FILE_EXT) || arg.endsWith(SQL_FILE_EXT)) {
          inputFiles.add(arg);
        } else {
          usageError("Don't know how to interpret argument '" + arg + "'", options);
        }
      }

      if (inputFiles.isEmpty()) {
        usageError("At least one input file must be supplied", options);
      }

      execCmd.inputFiles = inputFiles;

      return execCmd;
    }