public static void main(String args[]) {
    FileWriter writer = null;
    try {
      OptionParser parser = new OptionParser();
      ArgumentAcceptingOptionSpec<String> rootDirectoryOpt =
          parser.accepts("rootDirectory", "The root folder from which all the files will be migrated")
              .withRequiredArg()
              .describedAs("root_directory")
              .ofType(String.class);

      ArgumentAcceptingOptionSpec<String> hardwareLayoutOpt =
          parser.accepts("hardwareLayout", "The path of the hardware layout file")
              .withRequiredArg()
              .describedAs("hardware_layout")
              .ofType(String.class);

      ArgumentAcceptingOptionSpec<String> partitionLayoutOpt =
          parser.accepts("partitionLayout", "The path of the partition layout file")
              .withRequiredArg()
              .describedAs("partition_layout")
              .ofType(String.class);

      ArgumentAcceptingOptionSpec<Boolean> verboseLoggingOpt =
          parser.accepts("enableVerboseLogging", "Enables verbose logging")
              .withOptionalArg()
              .describedAs("Enable verbose logging")
              .ofType(Boolean.class)
              .defaultsTo(false);

      ArgumentAcceptingOptionSpec<String> partitionOpt =
          parser.accepts("partition", "The partition to which the put calls to be made against")
              .withRequiredArg()
              .describedAs("partition")
              .ofType(String.class);

      ArgumentAcceptingOptionSpec<String> datacenterOpt =
          parser.accepts("datacenter", "The datacenter to which the put calls to be made against")
              .withRequiredArg()
              .describedAs("datacenter")
              .ofType(String.class);

      ArgumentAcceptingOptionSpec<String> outFileOpt =
          parser.accepts("outFile", "The file to which output should be redirected")
              .withRequiredArg()
              .describedAs("outFile")
              .ofType(String.class);

      // Optional arguments for defining a specific node to write to.
      ArgumentAcceptingOptionSpec<String> nodeHostnameOpt =
          parser.accepts("nodeHostname", "The hostname of the node to put to (if specifying single node)")
              .withOptionalArg()
              .describedAs("nodeHostname")
              .ofType(String.class);

      ArgumentAcceptingOptionSpec<Integer> nodePortOpt =
          parser.accepts("nodePort", "The port of the node to put to (if specifying single node)")
              .withOptionalArg()
              .describedAs("nodePort")
              .ofType(Integer.class);

      OptionSet options = parser.parse(args);

      ArrayList<OptionSpec> listOpt = new ArrayList<>();
      listOpt.add(rootDirectoryOpt);
      listOpt.add(hardwareLayoutOpt);
      listOpt.add(partitionLayoutOpt);
      listOpt.add(partitionOpt);
      listOpt.add(datacenterOpt);
      listOpt.add(outFileOpt);

      ToolUtils.ensureOrExit(listOpt, options, parser);

      System.out.println("Starting to parse arguments");
      boolean enableVerboseLogging = options.has(verboseLoggingOpt);
      if (enableVerboseLogging) {
        System.out.println("Enabled verbose logging");
      }
      String rootDirectory = options.valueOf(rootDirectoryOpt);
      if (enableVerboseLogging) {
        System.out.println("Parsed rootdir " + rootDirectory);
      }
      String hardwareLayoutPath = options.valueOf(hardwareLayoutOpt);
      if (enableVerboseLogging) {
        System.out.println("Parsed Hardware layout " + hardwareLayoutPath);
      }
      String partitionLayoutPath = options.valueOf(partitionLayoutOpt);
      if (enableVerboseLogging) {
        System.out.println("Parsed partition layout " + partitionLayoutPath);
      }
      String partition = options.valueOf(partitionOpt);
      if (enableVerboseLogging) {
        System.out.println("Parsed partition " + partition);
      }
      partition = "Partition[" + partition + "]";
      String datacenter = options.valueOf(datacenterOpt);
      if (enableVerboseLogging) {
        System.out.println("Parsed datacenter " + datacenter);
      }
      String nodeHostname = options.valueOf(nodeHostnameOpt);
      if (enableVerboseLogging && nodeHostname != null) {
        System.out.println("Parsed node hostname " + nodeHostname);
      }
      Integer nodePort = options.valueOf(nodePortOpt);
      if (enableVerboseLogging && nodePort != null) {
        System.out.println("Parsed node port " + nodePort);
      }
      String outFile = options.valueOf(outFileOpt);
      if (enableVerboseLogging) {
        System.out.println("Parsed outFile " + outFile);
        System.out.println("Done parsing all args");
      }
      VerifiableProperties vprops = new VerifiableProperties((new Properties()));
      ClusterMapConfig clusterMapConfig = new ClusterMapConfig(vprops);
      ClusterMap map =
          ((ClusterAgentsFactory) Utils.getObj(clusterMapConfig.clusterMapClusterAgentsFactory, clusterMapConfig,
              hardwareLayoutPath, partitionLayoutPath)).getClusterMap();
      File logFile = new File(outFile);
      writer = new FileWriter(logFile);
      DirectoryUploader directoryUploader = new DirectoryUploader();
      directoryUploader.setPartitionId(map, partition, enableVerboseLogging);
      if (nodeHostname != null && nodePort != null) {
        directoryUploader.setDataNodeId(map, nodeHostname, nodePort, enableVerboseLogging);
      }
      directoryUploader.walkDirectoryToCreateBlobs(rootDirectory, writer, datacenter, map.getLocalDatacenterId(),
          enableVerboseLogging);
    } catch (Exception e) {
      System.err.println("Error on exit " + e);
    } finally {
      if (writer != null) {
        try {
          writer.close();
        } catch (Exception e) {
          System.out.println("Error when closing the writer");
        }
      }
    }
  }
Method to send PutRequest and receive PutResponse to and from a blocking channel. If it fails, blocking channel is destroyed

@param blockingChannel BlockingChannel used to send and receive request and response
@param putRequest      PutRequest which has to be sent through the blockingchannel
@param connectionPool  ConnectionPool from which connections are checked out
@return PutResponse the response from the PutRequest made
ambry-tools/src/main/java/com/github/ambry/tools/admin/DirectoryUploader.java