@Override
 public void handleRequest(final RestRequest request, final RestChannel channel, Client client) {
   DeleteIndexedScriptRequest deleteIndexedScriptRequest =
       new DeleteIndexedScriptRequest(getScriptLang(request), request.param("id"));
   deleteIndexedScriptRequest.version(
       request.paramAsLong("version", deleteIndexedScriptRequest.version()));
   deleteIndexedScriptRequest.versionType(
       VersionType.fromString(
           request.param("version_type"), deleteIndexedScriptRequest.versionType()));
   client.deleteIndexedScript(
       deleteIndexedScriptRequest,
       new RestBuilderListener<DeleteIndexedScriptResponse>(channel) {
         @Override
         public RestResponse buildResponse(
             DeleteIndexedScriptResponse result, XContentBuilder builder) throws Exception {
           builder
               .startObject()
               .field(Fields.FOUND, result.isFound())
               .field(Fields._INDEX, result.getIndex())
               .field(Fields._TYPE, result.getType())
               .field(Fields._ID, result.getId())
               .field(Fields._VERSION, result.getVersion())
               .endObject();
           RestStatus status = OK;
           if (!result.isFound()) {
             status = NOT_FOUND;
           }
           return new BytesRestResponse(status, builder);
         }
       });
 }
  private RestChannelConsumer parseExistingDocPercolate(
      PercolateRequest percolateRequest, RestRequest restRequest, NodeClient client) {
    String index = restRequest.param("index");
    String type = restRequest.param("type");
    percolateRequest.indices(
        Strings.splitStringByCommaToArray(restRequest.param("percolate_index", index)));
    percolateRequest.documentType(restRequest.param("percolate_type", type));

    GetRequest getRequest = new GetRequest(index, type, restRequest.param("id"));
    getRequest.routing(restRequest.param("routing"));
    getRequest.preference(restRequest.param("preference"));
    getRequest.refresh(restRequest.paramAsBoolean("refresh", getRequest.refresh()));
    getRequest.realtime(restRequest.paramAsBoolean("realtime", getRequest.realtime()));
    getRequest.version(RestActions.parseVersion(restRequest));
    getRequest.versionType(
        VersionType.fromString(restRequest.param("version_type"), getRequest.versionType()));

    percolateRequest.getRequest(getRequest);
    percolateRequest.routing(restRequest.param("percolate_routing"));
    percolateRequest.preference(restRequest.param("percolate_preference"));
    percolateRequest.source(restRequest.contentOrSourceParam());

    percolateRequest.indicesOptions(
        IndicesOptions.fromRequest(restRequest, percolateRequest.indicesOptions()));
    return channel -> executePercolate(client, percolateRequest, channel);
  }
  @Override
  public void handleRequest(
      final RestRequest request, final RestChannel channel, final NodeClient client) {
    DeleteRequest deleteRequest =
        new DeleteRequest(request.param("index"), request.param("type"), request.param("id"));
    deleteRequest.routing(request.param("routing"));
    deleteRequest.parent(
        request.param(
            "parent")); // order is important, set it after routing, so it will set the routing
    deleteRequest.timeout(request.paramAsTime("timeout", DeleteRequest.DEFAULT_TIMEOUT));
    deleteRequest.setRefreshPolicy(request.param("refresh"));
    deleteRequest.version(RestActions.parseVersion(request));
    deleteRequest.versionType(
        VersionType.fromString(request.param("version_type"), deleteRequest.versionType()));

    String consistencyLevel = request.param("consistency");
    if (consistencyLevel != null) {
      deleteRequest.consistencyLevel(WriteConsistencyLevel.fromString(consistencyLevel));
    }

    client.delete(deleteRequest, new RestStatusToXContentListener<>(channel));
  }
  public static void parseDocuments(
      XContentParser parser,
      List<Item> items,
      @Nullable String defaultIndex,
      @Nullable String defaultType,
      @Nullable String[] defaultFields,
      @Nullable FetchSourceContext defaultFetchSource,
      @Nullable String defaultRouting,
      boolean allowExplicitIndex)
      throws IOException {
    String currentFieldName = null;
    XContentParser.Token token;
    while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
      if (token != XContentParser.Token.START_OBJECT) {
        throw new IllegalArgumentException("docs array element should include an object");
      }
      String index = defaultIndex;
      String type = defaultType;
      String id = null;
      String routing = defaultRouting;
      String parent = null;
      List<String> fields = null;
      long version = Versions.MATCH_ANY;
      VersionType versionType = VersionType.INTERNAL;

      FetchSourceContext fetchSourceContext = null;

      while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
        if (token == XContentParser.Token.FIELD_NAME) {
          currentFieldName = parser.currentName();
        } else if (token.isValue()) {
          if ("_index".equals(currentFieldName)) {
            if (!allowExplicitIndex) {
              throw new IllegalArgumentException("explicit index in multi get is not allowed");
            }
            index = parser.text();
          } else if ("_type".equals(currentFieldName)) {
            type = parser.text();
          } else if ("_id".equals(currentFieldName)) {
            id = parser.text();
          } else if ("_routing".equals(currentFieldName) || "routing".equals(currentFieldName)) {
            routing = parser.text();
          } else if ("_parent".equals(currentFieldName) || "parent".equals(currentFieldName)) {
            parent = parser.text();
          } else if ("fields".equals(currentFieldName)) {
            fields = new ArrayList<>();
            fields.add(parser.text());
          } else if ("_version".equals(currentFieldName) || "version".equals(currentFieldName)) {
            version = parser.longValue();
          } else if ("_version_type".equals(currentFieldName)
              || "_versionType".equals(currentFieldName)
              || "version_type".equals(currentFieldName)
              || "versionType".equals(currentFieldName)) {
            versionType = VersionType.fromString(parser.text());
          } else if ("_source".equals(currentFieldName)) {
            if (parser.isBooleanValue()) {
              fetchSourceContext = new FetchSourceContext(parser.booleanValue());
            } else if (token == XContentParser.Token.VALUE_STRING) {
              fetchSourceContext = new FetchSourceContext(new String[] {parser.text()});
            } else {
              throw new ElasticsearchParseException("illegal type for _source: [{}]", token);
            }
          }
        } else if (token == XContentParser.Token.START_ARRAY) {
          if ("fields".equals(currentFieldName)) {
            fields = new ArrayList<>();
            while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
              fields.add(parser.text());
            }
          } else if ("_source".equals(currentFieldName)) {
            ArrayList<String> includes = new ArrayList<>();
            while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
              includes.add(parser.text());
            }
            fetchSourceContext = new FetchSourceContext(includes.toArray(Strings.EMPTY_ARRAY));
          }

        } else if (token == XContentParser.Token.START_OBJECT) {
          if ("_source".equals(currentFieldName)) {
            List<String> currentList = null, includes = null, excludes = null;

            while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
              if (token == XContentParser.Token.FIELD_NAME) {
                currentFieldName = parser.currentName();
                if ("includes".equals(currentFieldName) || "include".equals(currentFieldName)) {
                  currentList = includes != null ? includes : (includes = new ArrayList<>(2));
                } else if ("excludes".equals(currentFieldName)
                    || "exclude".equals(currentFieldName)) {
                  currentList = excludes != null ? excludes : (excludes = new ArrayList<>(2));
                } else {
                  throw new ElasticsearchParseException(
                      "source definition may not contain [{}]", parser.text());
                }
              } else if (token == XContentParser.Token.START_ARRAY) {
                while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
                  currentList.add(parser.text());
                }
              } else if (token.isValue()) {
                currentList.add(parser.text());
              } else {
                throw new ElasticsearchParseException(
                    "unexpected token while parsing source settings");
              }
            }

            fetchSourceContext =
                new FetchSourceContext(
                    includes == null
                        ? Strings.EMPTY_ARRAY
                        : includes.toArray(new String[includes.size()]),
                    excludes == null
                        ? Strings.EMPTY_ARRAY
                        : excludes.toArray(new String[excludes.size()]));
          }
        }
      }
      String[] aFields;
      if (fields != null) {
        aFields = fields.toArray(new String[fields.size()]);
      } else {
        aFields = defaultFields;
      }
      items.add(
          new Item(index, type, id)
              .routing(routing)
              .fields(aFields)
              .parent(parent)
              .version(version)
              .versionType(versionType)
              .fetchSourceContext(
                  fetchSourceContext == null ? defaultFetchSource : fetchSourceContext));
    }
  }
      private void parse(BytesReference data) throws Exception {
        XContent xContent = XContentFactory.xContent(data);
        String source = XContentBuilder.builder(xContent).string();
        int from = 0;
        int length = data.length();
        byte marker = xContent.streamSeparator();
        int nextMarker = findNextMarker(marker, from, data, length);
        if (nextMarker == -1) {
          nextMarker = length;
        }
        // now parse the action
        XContentParser parser = xContent.createParser(data.slice(from, nextMarker - from));

        try {
          // move pointers
          from = nextMarker + 1;

          // Move to START_OBJECT
          XContentParser.Token token = parser.nextToken();
          if (token == null) {
            throw new Exception("Wrong object structure");
          }
          assert token == XContentParser.Token.START_OBJECT;
          // Move to FIELD_NAME, that's the action
          // token = parser.nextToken();
          // assert token == XContentParser.Token.FIELD_NAME;
          // String action = parser.currentName();

          String id = null;
          String routing = null;
          String parent = null;
          String timestamp = null;
          Long ttl = null;
          String opType = null;
          long version = 0;
          VersionType versionType = VersionType.INTERNAL;
          String percolate = null;

          // at this stage, next token can either be END_OBJECT
          // (and use default index and type, with auto generated
          // id)
          // or START_OBJECT which will have another set of
          // parameters

          String currentFieldName = null;
          while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
            if (token == XContentParser.Token.FIELD_NAME) {
              currentFieldName = parser.currentName();
            } else if (token.isValue()) {
              if ("_index".equals(currentFieldName)) {
                index = parser.text();
              } else if ("_type".equals(currentFieldName)) {
                type = parser.text();
              } else if ("_queryString".equals(currentFieldName)) {
                queryString = parser.text();
              } else if ("_id".equals(currentFieldName)) {
                id = parser.text();
              } else if ("_routing".equals(currentFieldName)
                  || "routing".equals(currentFieldName)) {
                routing = parser.text();
              } else if ("_parent".equals(currentFieldName) || "parent".equals(currentFieldName)) {
                parent = parser.text();
              } else if ("_timestamp".equals(currentFieldName)
                  || "timestamp".equals(currentFieldName)) {
                timestamp = parser.text();
              } else if ("_ttl".equals(currentFieldName) || "ttl".equals(currentFieldName)) {
                if (parser.currentToken() == XContentParser.Token.VALUE_STRING) {
                  ttl = TimeValue.parseTimeValue(parser.text(), null).millis();
                } else {
                  ttl = parser.longValue();
                }
              } else if ("op_type".equals(currentFieldName) || "opType".equals(currentFieldName)) {
                opType = parser.text();
              } else if ("_version".equals(currentFieldName)
                  || "version".equals(currentFieldName)) {
                version = parser.longValue();
              } else if ("_version_type".equals(currentFieldName)
                  || "_versionType".equals(currentFieldName)
                  || "version_type".equals(currentFieldName)
                  || "versionType".equals(currentFieldName)) {
                versionType = VersionType.fromString(parser.text());
              } else if ("percolate".equals(currentFieldName)
                  || "_percolate".equals(currentFieldName)) {
                percolate = parser.textOrNull();
              }
            }
          }
          if (nextMarker < length) {
            nextMarker = findNextMarker(marker, from, data, length);
            if (nextMarker == -1) {
              nextMarker = length;
            }
            content = getString(data.slice(from, nextMarker - from));
          }

        } finally {
          parser.close();
        }
      }
  @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 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())));
  }