static List<DisplayHeader> buildDisplayHeaders(Table table, RestRequest request) {
    List<DisplayHeader> display = new ArrayList<>();
    if (request.hasParam("h")) {
      Set<String> headers = expandHeadersFromRequest(table, request);

      for (String possibility : headers) {
        DisplayHeader dispHeader = null;

        if (table.getAsMap().containsKey(possibility)) {
          dispHeader = new DisplayHeader(possibility, possibility);
        } else {
          for (Table.Cell headerCell : table.getHeaders()) {
            String aliases = headerCell.attr.get("alias");
            if (aliases != null) {
              for (String alias : Strings.splitStringByCommaToArray(aliases)) {
                if (possibility.equals(alias)) {
                  dispHeader = new DisplayHeader(headerCell.value.toString(), alias);
                  break;
                }
              }
            }
          }
        }

        if (dispHeader != null && checkOutputTimestamp(dispHeader, request)) {
          // We know we need the header asked for:
          display.add(dispHeader);

          // Look for accompanying sibling column
          Table.Cell hcell = table.getHeaderMap().get(dispHeader.name);
          String siblingFlag = hcell.attr.get("sibling");
          if (siblingFlag != null) {
            // ...link the sibling and check that its flag is set
            String sibling = siblingFlag + "." + dispHeader.name;
            Table.Cell c = table.getHeaderMap().get(sibling);
            if (c != null && request.paramAsBoolean(siblingFlag, false)) {
              display.add(
                  new DisplayHeader(c.value.toString(), siblingFlag + "." + dispHeader.display));
            }
          }
        }
      }
    } else {
      for (Table.Cell cell : table.getHeaders()) {
        String d = cell.attr.get("default");
        if (Booleans.parseBoolean(d, true)
            && checkOutputTimestamp(cell.value.toString(), request)) {
          display.add(new DisplayHeader(cell.value.toString(), cell.value.toString()));
        }
      }
    }
    return display;
  }
 @Override
 public void handleRequest(
     final RestRequest request, final RestChannel channel, final Client client)
     throws IOException {
   DeleteByQueryRequest delete =
       new DeleteByQueryRequest(Strings.splitStringByCommaToArray(request.param("index")));
   delete.indicesOptions(IndicesOptions.fromRequest(request, delete.indicesOptions()));
   delete.routing(request.param("routing"));
   if (request.hasParam("timeout")) {
     delete.timeout(request.paramAsTime("timeout", null));
   }
   if (request.hasContent()) {
     XContentParser requestParser =
         XContentFactory.xContent(request.content()).createParser(request.content());
     QueryParseContext context = new QueryParseContext(indicesQueriesRegistry);
     context.reset(requestParser);
     context.parseFieldMatcher(parseFieldMatcher);
     final QueryBuilder<?> builder = context.parseInnerQueryBuilder();
     delete.query(builder);
   } else {
     String source = request.param("source");
     if (source != null) {
       XContentParser requestParser = XContentFactory.xContent(source).createParser(source);
       QueryParseContext context = new QueryParseContext(indicesQueriesRegistry);
       context.reset(requestParser);
       final QueryBuilder<?> builder = context.parseInnerQueryBuilder();
       delete.query(builder);
     } else {
       QueryBuilder<?> queryBuilder = RestActions.urlParamsToQueryBuilder(request);
       if (queryBuilder != null) {
         delete.query(queryBuilder);
       }
     }
   }
   delete.types(Strings.splitStringByCommaToArray(request.param("type")));
   client.execute(INSTANCE, delete, new RestToXContentListener<DeleteByQueryResponse>(channel));
 }
  @Override
  public void handleRequest(final RestRequest request, final RestChannel channel) {
    UpdateRequest updateRequest =
        new UpdateRequest(request.param("index"), request.param("type"), request.param("id"));
    updateRequest.listenerThreaded(false);
    updateRequest.routing(request.param("routing"));
    updateRequest.parent(
        request.param(
            "parent")); // order is important, set it after routing, so it will set the routing
    updateRequest.timeout(request.paramAsTime("timeout", updateRequest.timeout()));
    updateRequest.refresh(request.paramAsBoolean("refresh", updateRequest.refresh()));
    String replicationType = request.param("replication");
    if (replicationType != null) {
      updateRequest.replicationType(ReplicationType.fromString(replicationType));
    }
    String consistencyLevel = request.param("consistency");
    if (consistencyLevel != null) {
      updateRequest.consistencyLevel(WriteConsistencyLevel.fromString(consistencyLevel));
    }
    updateRequest.percolate(request.param("percolate", null));
    updateRequest.script(request.param("script"));
    updateRequest.scriptLang(request.param("lang"));
    for (Map.Entry<String, String> entry : request.params().entrySet()) {
      if (entry.getKey().startsWith("sp_")) {
        updateRequest.addScriptParam(entry.getKey().substring(3), entry.getValue());
      }
    }
    String sField = request.param("fields");
    if (sField != null) {
      String[] sFields = Strings.splitStringByCommaToArray(sField);
      if (sFields != null) {
        updateRequest.fields(sFields);
      }
    }
    updateRequest.retryOnConflict(
        request.paramAsInt("retry_on_conflict", updateRequest.retryOnConflict()));

    // see if we have it in the body
    if (request.hasContent()) {
      try {
        updateRequest.source(
            request.contentByteArray(), request.contentByteArrayOffset(), request.contentLength());
        IndexRequest upsertRequest = updateRequest.upsertRequest();
        if (upsertRequest != null) {
          upsertRequest.routing(request.param("routing"));
          upsertRequest.parent(
              request.param(
                  "parent")); // order is important, set it after routing, so it will set the
          // routing
          upsertRequest.timestamp(request.param("timestamp"));
          if (request.hasParam("ttl")) {
            upsertRequest.ttl(request.paramAsTime("ttl", null).millis());
          }
          upsertRequest.version(RestActions.parseVersion(request));
          upsertRequest.versionType(
              VersionType.fromString(request.param("version_type"), upsertRequest.versionType()));
        }
        IndexRequest doc = updateRequest.doc();
        if (doc != null) {
          doc.routing(request.param("routing"));
          doc.parent(
              request.param(
                  "parent")); // order is important, set it after routing, so it will set the
          // routing
          doc.timestamp(request.param("timestamp"));
          if (request.hasParam("ttl")) {
            doc.ttl(request.paramAsTime("ttl", null).millis());
          }
          doc.version(RestActions.parseVersion(request));
          doc.versionType(VersionType.fromString(request.param("version_type"), doc.versionType()));
        }
      } catch (Exception e) {
        try {
          channel.sendResponse(new XContentThrowableRestResponse(request, e));
        } catch (IOException e1) {
          logger.warn("Failed to send response", e1);
        }
        return;
      }
    }

    client.update(
        updateRequest,
        new ActionListener<UpdateResponse>() {
          @Override
          public void onResponse(UpdateResponse response) {
            try {
              XContentBuilder builder = RestXContentBuilder.restContentBuilder(request);
              builder
                  .startObject()
                  .field(Fields.OK, true)
                  .field(Fields._INDEX, response.index())
                  .field(Fields._TYPE, response.type())
                  .field(Fields._ID, response.id())
                  .field(Fields._VERSION, response.version());

              if (response.getResult() != null) {
                builder.startObject(Fields.GET);
                response.getResult().toXContentEmbedded(builder, request);
                builder.endObject();
              }

              if (response.matches() != null) {
                builder.startArray(Fields.MATCHES);
                for (String match : response.matches()) {
                  builder.value(match);
                }
                builder.endArray();
              }
              builder.endObject();
              RestStatus status = OK;
              if (response.version() == 1) {
                status = CREATED;
              }
              channel.sendResponse(new XContentRestResponse(request, status, builder));
            } catch (Exception e) {
              onFailure(e);
            }
          }

          @Override
          public void onFailure(Throwable e) {
            try {
              channel.sendResponse(new XContentThrowableRestResponse(request, e));
            } catch (IOException e1) {
              logger.error("Failed to send failure response", e1);
            }
          }
        });
  }
  @Override
  public void handleRequest(
      final RestRequest request, final RestChannel channel, final Client client) {
    IndicesStatsRequest indicesStatsRequest = new IndicesStatsRequest();
    indicesStatsRequest.indicesOptions(
        IndicesOptions.fromRequest(request, indicesStatsRequest.indicesOptions()));
    indicesStatsRequest.indices(Strings.splitStringByCommaToArray(request.param("index")));
    indicesStatsRequest.types(Strings.splitStringByCommaToArray(request.param("types")));

    Set<String> metrics = Strings.splitStringByCommaToSet(request.param("metric", "_all"));
    // short cut, if no metrics have been specified in URI
    if (metrics.size() == 1 && metrics.contains("_all")) {
      indicesStatsRequest.all();
    } else {
      indicesStatsRequest.clear();
      indicesStatsRequest.docs(metrics.contains("docs"));
      indicesStatsRequest.store(metrics.contains("store"));
      indicesStatsRequest.indexing(metrics.contains("indexing"));
      indicesStatsRequest.search(metrics.contains("search"));
      indicesStatsRequest.get(metrics.contains("get"));
      indicesStatsRequest.merge(metrics.contains("merge"));
      indicesStatsRequest.refresh(metrics.contains("refresh"));
      indicesStatsRequest.flush(metrics.contains("flush"));
      indicesStatsRequest.warmer(metrics.contains("warmer"));
      indicesStatsRequest.queryCache(metrics.contains("query_cache"));
      indicesStatsRequest.percolate(metrics.contains("percolate"));
      indicesStatsRequest.segments(metrics.contains("segments"));
      indicesStatsRequest.fieldData(metrics.contains("fielddata"));
      indicesStatsRequest.completion(metrics.contains("completion"));
      indicesStatsRequest.suggest(metrics.contains("suggest"));
      indicesStatsRequest.requestCache(metrics.contains("request_cache"));
      indicesStatsRequest.recovery(metrics.contains("recovery"));
      indicesStatsRequest.translog(metrics.contains("translog"));
    }

    if (request.hasParam("groups")) {
      indicesStatsRequest.groups(Strings.splitStringByCommaToArray(request.param("groups")));
    }

    if (request.hasParam("types")) {
      indicesStatsRequest.types(Strings.splitStringByCommaToArray(request.param("types")));
    }

    if (indicesStatsRequest.completion()
        && (request.hasParam("fields") || request.hasParam("completion_fields"))) {
      indicesStatsRequest.completionFields(
          request.paramAsStringArray(
              "completion_fields", request.paramAsStringArray("fields", Strings.EMPTY_ARRAY)));
    }

    if (indicesStatsRequest.fieldData()
        && (request.hasParam("fields") || request.hasParam("fielddata_fields"))) {
      indicesStatsRequest.fieldDataFields(
          request.paramAsStringArray(
              "fielddata_fields", request.paramAsStringArray("fields", Strings.EMPTY_ARRAY)));
    }

    client
        .admin()
        .indices()
        .stats(
            indicesStatsRequest,
            new RestBuilderListener<IndicesStatsResponse>(channel) {
              @Override
              public RestResponse buildResponse(
                  IndicesStatsResponse response, XContentBuilder builder) throws Exception {
                builder.startObject();
                buildBroadcastShardsHeader(builder, request, response);
                response.toXContent(builder, request);
                builder.endObject();
                return new BytesRestResponse(OK, builder);
              }
            });
  }
  public static SearchSourceBuilder parseSearchSource(RestRequest request) {
    SearchSourceBuilder searchSourceBuilder = null;

    QuerySourceBuilder querySourceBuilder = RestActions.parseQuerySource(request);
    if (querySourceBuilder != null) {
      searchSourceBuilder = new SearchSourceBuilder();
      searchSourceBuilder.query(querySourceBuilder);
    }

    int from = request.paramAsInt("from", -1);
    if (from != -1) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      searchSourceBuilder.from(from);
    }
    int size = request.paramAsInt("size", -1);
    if (size != -1) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      searchSourceBuilder.size(size);
    }

    if (request.hasParam("explain")) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      searchSourceBuilder.explain(request.paramAsBoolean("explain", null));
    }
    if (request.hasParam("version")) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      searchSourceBuilder.version(request.paramAsBoolean("version", null));
    }
    if (request.hasParam("timeout")) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      searchSourceBuilder.timeout(request.paramAsTime("timeout", null));
    }
    if (request.hasParam("terminate_after")) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      int terminateAfter =
          request.paramAsInt("terminate_after", SearchContext.DEFAULT_TERMINATE_AFTER);
      if (terminateAfter < 0) {
        throw new IllegalArgumentException("terminateAfter must be > 0");
      } else if (terminateAfter > 0) {
        searchSourceBuilder.terminateAfter(terminateAfter);
      }
    }

    String sField = request.param("fields");
    if (sField != null) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      if (!Strings.hasText(sField)) {
        searchSourceBuilder.noFields();
      } else {
        String[] sFields = Strings.splitStringByCommaToArray(sField);
        if (sFields != null) {
          for (String field : sFields) {
            searchSourceBuilder.field(field);
          }
        }
      }
    }
    String sFieldDataFields = request.param("fielddata_fields");
    if (sFieldDataFields != null) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      if (Strings.hasText(sFieldDataFields)) {
        String[] sFields = Strings.splitStringByCommaToArray(sFieldDataFields);
        if (sFields != null) {
          for (String field : sFields) {
            searchSourceBuilder.fieldDataField(field);
          }
        }
      }
    }
    FetchSourceContext fetchSourceContext = FetchSourceContext.parseFromRestRequest(request);
    if (fetchSourceContext != null) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      searchSourceBuilder.fetchSource(fetchSourceContext);
    }

    if (request.hasParam("track_scores")) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      searchSourceBuilder.trackScores(request.paramAsBoolean("track_scores", false));
    }

    String sSorts = request.param("sort");
    if (sSorts != null) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      String[] sorts = Strings.splitStringByCommaToArray(sSorts);
      for (String sort : sorts) {
        int delimiter = sort.lastIndexOf(":");
        if (delimiter != -1) {
          String sortField = sort.substring(0, delimiter);
          String reverse = sort.substring(delimiter + 1);
          if ("asc".equals(reverse)) {
            searchSourceBuilder.sort(sortField, SortOrder.ASC);
          } else if ("desc".equals(reverse)) {
            searchSourceBuilder.sort(sortField, SortOrder.DESC);
          }
        } else {
          searchSourceBuilder.sort(sort);
        }
      }
    }

    String sStats = request.param("stats");
    if (sStats != null) {
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      searchSourceBuilder.stats(Strings.splitStringByCommaToArray(sStats));
    }

    String suggestField = request.param("suggest_field");
    if (suggestField != null) {
      String suggestText = request.param("suggest_text", request.param("q"));
      int suggestSize = request.paramAsInt("suggest_size", 5);
      if (searchSourceBuilder == null) {
        searchSourceBuilder = new SearchSourceBuilder();
      }
      String suggestMode = request.param("suggest_mode");
      searchSourceBuilder
          .suggest()
          .addSuggestion(
              termSuggestion(suggestField)
                  .field(suggestField)
                  .text(suggestText)
                  .size(suggestSize)
                  .suggestMode(suggestMode));
    }

    return searchSourceBuilder;
  }
  @Override
  public void handleRequest(final RestRequest request, final RestChannel channel) {
    String[] nodesIds = Strings.splitStringByCommaToArray(request.param("nodeId"));
    Set<String> metrics = Strings.splitStringByCommaToSet(request.param("metric", "_all"));

    NodesStatsRequest nodesStatsRequest = new NodesStatsRequest(nodesIds);
    nodesStatsRequest.listenerThreaded(false);

    if (metrics.size() == 1 && metrics.contains("_all")) {
      nodesStatsRequest.all();
      nodesStatsRequest.indices(CommonStatsFlags.ALL);
    } else {
      nodesStatsRequest.clear();
      nodesStatsRequest.os(metrics.contains("os"));
      nodesStatsRequest.jvm(metrics.contains("jvm"));
      nodesStatsRequest.threadPool(metrics.contains("thread_pool"));
      nodesStatsRequest.network(metrics.contains("network"));
      nodesStatsRequest.fs(metrics.contains("fs"));
      nodesStatsRequest.transport(metrics.contains("transport"));
      nodesStatsRequest.http(metrics.contains("http"));
      nodesStatsRequest.indices(metrics.contains("indices"));
      nodesStatsRequest.process(metrics.contains("process"));
      nodesStatsRequest.breaker(metrics.contains("breaker"));

      // check for index specific metrics
      if (metrics.contains("indices")) {
        Set<String> indexMetrics =
            Strings.splitStringByCommaToSet(request.param("indexMetric", "_all"));
        if (indexMetrics.size() == 1 && indexMetrics.contains("_all")) {
          nodesStatsRequest.indices(CommonStatsFlags.ALL);
        } else {
          CommonStatsFlags flags = new CommonStatsFlags();
          for (Flag flag : CommonStatsFlags.Flag.values()) {
            flags.set(flag, indexMetrics.contains(flag.getRestName()));
          }
          nodesStatsRequest.indices(flags);
        }
      }
    }

    if (nodesStatsRequest.indices().isSet(Flag.FieldData)
        && (request.hasParam("fields") || request.hasParam("fielddata_fields"))) {
      nodesStatsRequest
          .indices()
          .fieldDataFields(
              request.paramAsStringArray(
                  "fielddata_fields", request.paramAsStringArray("fields", null)));
    }
    if (nodesStatsRequest.indices().isSet(Flag.Completion)
        && (request.hasParam("fields") || request.hasParam("completion_fields"))) {
      nodesStatsRequest
          .indices()
          .completionDataFields(
              request.paramAsStringArray(
                  "completion_fields", request.paramAsStringArray("fields", null)));
    }
    if (nodesStatsRequest.indices().isSet(Flag.Search) && (request.hasParam("groups"))) {
      nodesStatsRequest.indices().groups(request.paramAsStringArray("groups", null));
    }
    if (nodesStatsRequest.indices().isSet(Flag.Indexing) && (request.hasParam("types"))) {
      nodesStatsRequest.indices().types(request.paramAsStringArray("types", null));
    }

    client
        .admin()
        .cluster()
        .nodesStats(
            nodesStatsRequest,
            new ActionListener<NodesStatsResponse>() {
              @Override
              public void onResponse(NodesStatsResponse response) {
                try {
                  XContentBuilder builder = RestXContentBuilder.restContentBuilder(request);
                  builder.startObject();
                  response.toXContent(builder, request);
                  builder.endObject();
                  channel.sendResponse(new BytesRestResponse(RestStatus.OK, builder));
                } catch (Throwable e) {
                  onFailure(e);
                }
              }

              @Override
              public void onFailure(Throwable e) {
                try {
                  channel.sendResponse(new BytesRestResponse(request, e));
                } catch (IOException e1) {
                  logger.error("Failed to send failure response", e1);
                }
              }
            });
  }
  @Override
  public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client)
      throws IOException {
    UpdateRequest updateRequest =
        new UpdateRequest(request.param("index"), request.param("type"), request.param("id"));
    updateRequest.routing(request.param("routing"));
    updateRequest.parent(request.param("parent"));
    updateRequest.timeout(request.paramAsTime("timeout", updateRequest.timeout()));
    updateRequest.setRefreshPolicy(request.param("refresh"));
    String waitForActiveShards = request.param("wait_for_active_shards");
    if (waitForActiveShards != null) {
      updateRequest.waitForActiveShards(ActiveShardCount.parseString(waitForActiveShards));
    }
    updateRequest.docAsUpsert(request.paramAsBoolean("doc_as_upsert", updateRequest.docAsUpsert()));
    FetchSourceContext fetchSourceContext = FetchSourceContext.parseFromRestRequest(request);
    String sField = request.param("fields");
    if (sField != null && fetchSourceContext != null) {
      throw new IllegalArgumentException(
          "[fields] and [_source] cannot be used in the same request");
    }
    if (sField != null) {
      DEPRECATION_LOGGER.deprecated("Deprecated field [fields] used, expected [_source] instead");
      String[] sFields = Strings.splitStringByCommaToArray(sField);
      updateRequest.fields(sFields);
    } else if (fetchSourceContext != null) {
      updateRequest.fetchSource(fetchSourceContext);
    }

    updateRequest.retryOnConflict(
        request.paramAsInt("retry_on_conflict", updateRequest.retryOnConflict()));
    updateRequest.version(RestActions.parseVersion(request));
    updateRequest.versionType(
        VersionType.fromString(request.param("version_type"), updateRequest.versionType()));

    // see if we have it in the body
    if (request.hasContent()) {
      updateRequest.fromXContent(request.content());
      IndexRequest upsertRequest = updateRequest.upsertRequest();
      if (upsertRequest != null) {
        upsertRequest.routing(request.param("routing"));
        upsertRequest.parent(
            request.param(
                "parent")); // order is important, set it after routing, so it will set the routing
        upsertRequest.timestamp(request.param("timestamp"));
        if (request.hasParam("ttl")) {
          upsertRequest.ttl(request.param("ttl"));
        }
        upsertRequest.version(RestActions.parseVersion(request));
        upsertRequest.versionType(
            VersionType.fromString(request.param("version_type"), upsertRequest.versionType()));
      }
      IndexRequest doc = updateRequest.doc();
      if (doc != null) {
        doc.routing(request.param("routing"));
        doc.parent(
            request.param(
                "parent")); // order is important, set it after routing, so it will set the routing
        doc.timestamp(request.param("timestamp"));
        if (request.hasParam("ttl")) {
          doc.ttl(request.param("ttl"));
        }
        doc.version(RestActions.parseVersion(request));
        doc.versionType(VersionType.fromString(request.param("version_type"), doc.versionType()));
      }
    }

    return channel ->
        client.update(
            updateRequest,
            new RestStatusToXContentListener<>(
                channel, r -> r.getLocation(updateRequest.routing())));
  }
  @Override
  public void handleRequest(final RestRequest request, final RestChannel channel) {
    OptimizeRequest optimizeRequest =
        new OptimizeRequest(RestActions.splitIndices(request.param("index")));
    optimizeRequest.listenerThreaded(false);
    if (request.hasParam("ignore_indices")) {
      optimizeRequest.ignoreIndices(IgnoreIndices.fromString(request.param("ignore_indices")));
    }
    try {
      optimizeRequest.waitForMerge(
          request.paramAsBoolean("wait_for_merge", optimizeRequest.waitForMerge()));
      optimizeRequest.maxNumSegments(
          request.paramAsInt("max_num_segments", optimizeRequest.maxNumSegments()));
      optimizeRequest.onlyExpungeDeletes(
          request.paramAsBoolean("only_expunge_deletes", optimizeRequest.onlyExpungeDeletes()));
      optimizeRequest.flush(request.paramAsBoolean("flush", optimizeRequest.flush()));
      optimizeRequest.refresh(request.paramAsBoolean("refresh", optimizeRequest.refresh()));

      BroadcastOperationThreading operationThreading =
          BroadcastOperationThreading.fromString(
              request.param("operation_threading"), BroadcastOperationThreading.SINGLE_THREAD);
      if (operationThreading == BroadcastOperationThreading.NO_THREADS) {
        // since we don't spawn, don't allow no_threads, but change it to a single thread
        operationThreading = BroadcastOperationThreading.THREAD_PER_SHARD;
      }
      optimizeRequest.operationThreading(operationThreading);
    } catch (Exception e) {
      try {
        XContentBuilder builder = RestXContentBuilder.restContentBuilder(request);
        channel.sendResponse(
            new XContentRestResponse(
                request,
                BAD_REQUEST,
                builder.startObject().field("error", e.getMessage()).endObject()));
      } catch (IOException e1) {
        logger.error("Failed to send failure response", e1);
      }
      return;
    }
    client
        .admin()
        .indices()
        .optimize(
            optimizeRequest,
            new ActionListener<OptimizeResponse>() {
              @Override
              public void onResponse(OptimizeResponse response) {
                try {
                  XContentBuilder builder = RestXContentBuilder.restContentBuilder(request);
                  builder.startObject();
                  builder.field("ok", true);

                  buildBroadcastShardsHeader(builder, response);

                  builder.endObject();
                  channel.sendResponse(new XContentRestResponse(request, OK, builder));
                } catch (Throwable e) {
                  onFailure(e);
                }
              }

              @Override
              public void onFailure(Throwable e) {
                try {
                  channel.sendResponse(new XContentThrowableRestResponse(request, e));
                } catch (IOException e1) {
                  logger.error("Failed to send failure response", e1);
                }
              }
            });
  }