protected TransportShardReplicationOperationAction(
      Settings settings,
      TransportService transportService,
      ClusterService clusterService,
      IndicesService indicesService,
      ThreadPool threadPool,
      ShardStateAction shardStateAction) {
    super(settings, threadPool);
    this.transportService = transportService;
    this.clusterService = clusterService;
    this.indicesService = indicesService;
    this.shardStateAction = shardStateAction;

    this.transportAction = transportAction();
    this.transportReplicaAction = transportReplicaAction();
    this.executor = executor();
    this.checkWriteConsistency = checkWriteConsistency();

    transportService.registerHandler(transportAction, new OperationTransportHandler());
    transportService.registerHandler(
        transportReplicaAction, new ReplicaOperationTransportHandler());

    this.transportOptions = transportOptions();

    this.defaultReplicationType =
        ReplicationType.fromString(settings.get("action.replication_type", "sync"));
    this.defaultWriteConsistencyLevel =
        WriteConsistencyLevel.fromString(settings.get("action.write_consistency", "quorum"));
  }
 @Override
 public void readFrom(StreamInput in) throws IOException {
   super.readFrom(in);
   replicationType = ReplicationType.fromId(in.readByte());
   consistencyLevel = WriteConsistencyLevel.fromId(in.readByte());
   timeout = TimeValue.readTimeValue(in);
   index = in.readString();
 }
 @Override
 public void writeTo(StreamOutput out) throws IOException {
   super.writeTo(out);
   out.writeByte(replicationType.id());
   out.writeByte(consistencyLevel.id());
   timeout.writeTo(out);
   out.writeString(index);
 }
 @Override
 public void writeTo(StreamOutput out) throws IOException {
   super.writeTo(out);
   out.writeByte(replicationType.id());
   out.writeByte(consistencyLevel.id());
   timeout.writeTo(out);
   out.writeStringArrayNullable(indices);
   indicesOptions.writeIndicesOptions(out);
 }
 @Override
 public void readFrom(StreamInput in) throws IOException {
   super.readFrom(in);
   if (in.readBoolean()) {
     shardId = ShardId.readShardId(in);
   } else {
     shardId = null;
   }
   consistencyLevel = WriteConsistencyLevel.fromId(in.readByte());
   timeout = TimeValue.readTimeValue(in);
   index = in.readString();
 }
 @Override
 public void writeTo(StreamOutput out) throws IOException {
   super.writeTo(out);
   if (shardId != null) {
     out.writeBoolean(true);
     shardId.writeTo(out);
   } else {
     out.writeBoolean(false);
   }
   out.writeByte(consistencyLevel.id());
   timeout.writeTo(out);
   out.writeString(index);
 }
  protected TransportReplicationAction(
      Settings settings,
      String actionName,
      TransportService transportService,
      ClusterService clusterService,
      IndicesService indicesService,
      ThreadPool threadPool,
      ShardStateAction shardStateAction,
      MappingUpdatedAction mappingUpdatedAction,
      ActionFilters actionFilters,
      IndexNameExpressionResolver indexNameExpressionResolver,
      Supplier<Request> request,
      Supplier<ReplicaRequest> replicaRequest,
      String executor) {
    super(settings, actionName, threadPool, actionFilters, indexNameExpressionResolver);
    this.transportService = transportService;
    this.clusterService = clusterService;
    this.indicesService = indicesService;
    this.shardStateAction = shardStateAction;
    this.mappingUpdatedAction = mappingUpdatedAction;

    this.transportReplicaAction = actionName + "[r]";
    this.executor = executor;
    this.checkWriteConsistency = checkWriteConsistency();

    transportService.registerRequestHandler(
        actionName, request, ThreadPool.Names.SAME, new OperationTransportHandler());
    // we must never reject on because of thread pool capacity on replicas
    transportService.registerRequestHandler(
        transportReplicaAction,
        replicaRequest,
        executor,
        true,
        new ReplicaOperationTransportHandler());

    this.transportOptions = transportOptions();

    this.defaultWriteConsistencyLevel =
        WriteConsistencyLevel.fromString(settings.get("action.write_consistency", "quorum"));
    // TODO: set a default timeout
    shardFailedTimeout = settings.getAsTime(SHARD_FAILURE_TIMEOUT, null);
  }
  @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));
  }
  @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);
            }
          }
        });
  }