public static LoaderOptions parseArgs(String cmdArgs[]) {
      CommandLineParser parser = new GnuParser();
      CmdLineOptions options = getCmdLineOptions();
      try {
        CommandLine cmd = parser.parse(options, cmdArgs, false);

        if (cmd.hasOption(HELP_OPTION)) {
          printUsage(options);
          System.exit(0);
        }

        String[] args = cmd.getArgs();
        if (args.length == 0) {
          System.err.println("Missing sstable directory argument");
          printUsage(options);
          System.exit(1);
        }

        if (args.length > 1) {
          System.err.println("Too many arguments");
          printUsage(options);
          System.exit(1);
        }

        String dirname = args[0];
        File dir = new File(dirname);

        if (!dir.exists()) errorMsg("Unknown directory: " + dirname, options);

        if (!dir.isDirectory()) errorMsg(dirname + " is not a directory", options);

        LoaderOptions opts = new LoaderOptions(dir);

        opts.debug = cmd.hasOption(DEBUG_OPTION);
        opts.verbose = cmd.hasOption(VERBOSE_OPTION);
        opts.noProgress = cmd.hasOption(NOPROGRESS_OPTION);

        if (cmd.hasOption(IGNORE_NODES_OPTION)) {
          String[] nodes = cmd.getOptionValue(IGNORE_NODES_OPTION).split(",");
          try {
            for (String node : nodes) {
              opts.ignores.add(InetAddress.getByName(node));
            }
          } catch (UnknownHostException e) {
            errorMsg(e.getMessage(), options);
          }
        }

        return opts;
      } catch (ParseException e) {
        errorMsg(e.getMessage(), options);
        return null;
      }
    }
  public static void main(String args[]) throws IOException {
    LoaderOptions options = LoaderOptions.parseArgs(args);
    try {
      SSTableLoader loader =
          new SSTableLoader(options.directory, new ExternalClient(options), options);
      SSTableLoader.LoaderFuture future = loader.stream(options.ignores);

      if (options.noProgress) {
        future.get();
      } else {
        ProgressIndicator indicator = new ProgressIndicator(future.getPendingFiles());
        indicator.start();
        System.out.println("");
        while (!future.isDone()) {
          if (indicator.printProgress()) {
            // We're done with streaming
            System.out.println("\nWaiting for targets to rebuild indexes ...");
            future.get();
            assert future.isDone();
          } else {
            try {
              Thread.sleep(1000L);
            } catch (Exception e) {
            }
          }
        }
      }

      System.exit(0); // We need that to stop non daemonized threads
    } catch (Exception e) {
      System.err.println(e.getMessage());
      if (options.debug) e.printStackTrace(System.err);
      System.exit(1);
    }
  }
  public static void main(String args[]) {
    Config.setClientMode(true);
    LoaderOptions options = LoaderOptions.parseArgs(args);
    OutputHandler handler = new OutputHandler.SystemOutput(options.verbose, options.debug);
    SSTableLoader loader =
        new SSTableLoader(
            options.directory,
            new ExternalClient(
                options.hosts,
                options.rpcPort,
                options.user,
                options.passwd,
                options.transportFactory,
                options.storagePort,
                options.sslStoragePort,
                options.serverEncOptions),
            handler);
    DatabaseDescriptor.setStreamThroughputOutboundMegabitsPerSec(options.throttle);
    StreamResultFuture future = null;
    try {
      if (options.noProgress) future = loader.stream(options.ignores);
      else future = loader.stream(options.ignores, new ProgressIndicator());
    } catch (Exception e) {
      System.err.println(e.getMessage());
      if (e.getCause() != null) System.err.println(e.getCause());
      if (options.debug) e.printStackTrace(System.err);
      else System.err.println("Run with --debug to get full stack trace or --help to get help.");
      System.exit(1);
    }

    handler.output(String.format("Streaming session ID: %s", future.planId));

    try {
      future.get();
      System.exit(0); // We need that to stop non daemonized threads
    } catch (Exception e) {
      System.err.println("Streaming to the following hosts failed:");
      System.err.println(loader.getFailedHosts());
      System.err.println(e);
      if (options.debug) e.printStackTrace(System.err);
      System.exit(1);
    }
  }
    public static LoaderOptions parseArgs(String cmdArgs[]) {
      CommandLineParser parser = new GnuParser();
      CmdLineOptions options = getCmdLineOptions();
      try {
        CommandLine cmd = parser.parse(options, cmdArgs, false);

        if (cmd.hasOption(HELP_OPTION)) {
          printUsage(options);
          System.exit(0);
        }

        String[] args = cmd.getArgs();
        if (args.length == 0) {
          System.err.println("Missing sstable directory argument");
          printUsage(options);
          System.exit(1);
        }

        if (args.length > 1) {
          System.err.println("Too many arguments");
          printUsage(options);
          System.exit(1);
        }

        String dirname = args[0];
        File dir = new File(dirname);

        if (!dir.exists()) errorMsg("Unknown directory: " + dirname, options);

        if (!dir.isDirectory()) errorMsg(dirname + " is not a directory", options);

        LoaderOptions opts = new LoaderOptions(dir);

        opts.debug = cmd.hasOption(DEBUG_OPTION);
        opts.verbose = cmd.hasOption(VERBOSE_OPTION);
        opts.noProgress = cmd.hasOption(NOPROGRESS_OPTION);

        if (cmd.hasOption(RPC_PORT_OPTION))
          opts.rpcPort = Integer.parseInt(cmd.getOptionValue(RPC_PORT_OPTION));

        if (cmd.hasOption(USER_OPTION)) opts.user = cmd.getOptionValue(USER_OPTION);

        if (cmd.hasOption(PASSWD_OPTION)) opts.passwd = cmd.getOptionValue(PASSWD_OPTION);

        if (cmd.hasOption(INITIAL_HOST_ADDRESS_OPTION)) {
          String[] nodes = cmd.getOptionValue(INITIAL_HOST_ADDRESS_OPTION).split(",");
          try {
            for (String node : nodes) {
              opts.hosts.add(InetAddress.getByName(node.trim()));
            }
          } catch (UnknownHostException e) {
            errorMsg("Unknown host: " + e.getMessage(), options);
          }

        } else {
          System.err.println("Initial hosts must be specified (-d)");
          printUsage(options);
          System.exit(1);
        }

        if (cmd.hasOption(IGNORE_NODES_OPTION)) {
          String[] nodes = cmd.getOptionValue(IGNORE_NODES_OPTION).split(",");
          try {
            for (String node : nodes) {
              opts.ignores.add(InetAddress.getByName(node.trim()));
            }
          } catch (UnknownHostException e) {
            errorMsg("Unknown host: " + e.getMessage(), options);
          }
        }

        // try to load config file first, so that values can be rewritten with other option values.
        // otherwise use default config.
        Config config;
        if (cmd.hasOption(CONFIG_PATH)) {
          File configFile = new File(cmd.getOptionValue(CONFIG_PATH));
          if (!configFile.exists()) {
            errorMsg("Config file not found", options);
          }
          config = new YamlConfigurationLoader().loadConfig(configFile.toURI().toURL());
        } else {
          config = new Config();
        }
        opts.storagePort = config.storage_port;
        opts.sslStoragePort = config.ssl_storage_port;
        opts.throttle = config.stream_throughput_outbound_megabits_per_sec;
        opts.encOptions = config.client_encryption_options;
        opts.serverEncOptions = config.server_encryption_options;

        if (cmd.hasOption(THROTTLE_MBITS)) {
          opts.throttle = Integer.parseInt(cmd.getOptionValue(THROTTLE_MBITS));
        }

        if (cmd.hasOption(SSL_TRUSTSTORE)) {
          opts.encOptions.truststore = cmd.getOptionValue(SSL_TRUSTSTORE);
        }

        if (cmd.hasOption(SSL_TRUSTSTORE_PW)) {
          opts.encOptions.truststore_password = cmd.getOptionValue(SSL_TRUSTSTORE_PW);
        }

        if (cmd.hasOption(SSL_KEYSTORE)) {
          opts.encOptions.keystore = cmd.getOptionValue(SSL_KEYSTORE);
          // if a keystore was provided, lets assume we'll need to use it
          opts.encOptions.require_client_auth = true;
        }

        if (cmd.hasOption(SSL_KEYSTORE_PW)) {
          opts.encOptions.keystore_password = cmd.getOptionValue(SSL_KEYSTORE_PW);
        }

        if (cmd.hasOption(SSL_PROTOCOL)) {
          opts.encOptions.protocol = cmd.getOptionValue(SSL_PROTOCOL);
        }

        if (cmd.hasOption(SSL_ALGORITHM)) {
          opts.encOptions.algorithm = cmd.getOptionValue(SSL_ALGORITHM);
        }

        if (cmd.hasOption(SSL_STORE_TYPE)) {
          opts.encOptions.store_type = cmd.getOptionValue(SSL_STORE_TYPE);
        }

        if (cmd.hasOption(SSL_CIPHER_SUITES)) {
          opts.encOptions.cipher_suites = cmd.getOptionValue(SSL_CIPHER_SUITES).split(",");
        }

        if (cmd.hasOption(TRANSPORT_FACTORY)) {
          ITransportFactory transportFactory =
              getTransportFactory(cmd.getOptionValue(TRANSPORT_FACTORY));
          configureTransportFactory(transportFactory, opts);
          opts.transportFactory = transportFactory;
        }

        return opts;
      } catch (ParseException | ConfigurationException | MalformedURLException e) {
        errorMsg(e.getMessage(), options);
        return null;
      }
    }