private AsyncSingleAction(Request request, ActionListener<Response> listener) {
      this.listener = listener;

      ClusterState clusterState = clusterService.state();
      nodes = clusterState.nodes();
      ClusterBlockException blockException = checkGlobalBlock(clusterState);
      if (blockException != null) {
        throw blockException;
      }

      String concreteSingleIndex;
      if (resolveIndex(request)) {
        concreteSingleIndex =
            clusterState.metaData().concreteSingleIndex(request.index(), request.indicesOptions());
      } else {
        concreteSingleIndex = request.index();
      }
      this.internalRequest = new InternalRequest(request, concreteSingleIndex);

      blockException = checkRequestBlock(clusterState, internalRequest);
      if (blockException != null) {
        throw blockException;
      }
      this.shardsIt = shards(clusterState, internalRequest);
    }
    protected AsyncBroadcastAction(Request request, ActionListener<Response> listener) {
      this.request = request;
      this.listener = listener;

      clusterState = clusterService.state();

      ClusterBlockException blockException = checkGlobalBlock(clusterState, request);
      if (blockException != null) {
        throw blockException;
      }
      // update to concrete indices
      String[] concreteIndices =
          clusterState.metaData().concreteIndices(request.indicesOptions(), request.indices());
      blockException = checkRequestBlock(clusterState, request, concreteIndices);
      if (blockException != null) {
        throw blockException;
      }

      nodes = clusterState.nodes();
      logger.trace("resolving shards based on cluster state version [{}]", clusterState.version());
      shardsIts = shards(clusterState, request, concreteIndices);
      expectedOps = shardsIts.size();

      shardsResponses = new AtomicReferenceArray<Object>(expectedOps);
    }
 @Override
 protected final void masterOperation(
     final Request request, final ClusterState state, final ActionListener<Response> listener)
     throws ElasticsearchException {
   String[] concreteIndices =
       state.metaData().concreteIndices(request.indicesOptions(), request.indices());
   doMasterOperation(request, concreteIndices, state, listener);
 }
 public IndicesOptions indicesOptions() {
   return indicesLevelRequest.indicesOptions();
 }
  @Override
  protected void doExecute(final Request request, final ActionListener<Response> listener) {
    ClusterState clusterState = clusterService.state();
    ClusterBlockException blockException = checkGlobalBlock(clusterState, request);
    if (blockException != null) {
      throw blockException;
    }
    // update to concrete index
    request.index(
        clusterState.metaData().concreteSingleIndex(request.index(), request.indicesOptions()));
    blockException = checkRequestBlock(clusterState, request);
    if (blockException != null) {
      throw blockException;
    }

    GroupShardsIterator groups;
    try {
      groups = shards(request);
    } catch (Throwable e) {
      listener.onFailure(e);
      return;
    }
    final AtomicInteger indexCounter = new AtomicInteger();
    final AtomicInteger failureCounter = new AtomicInteger();
    final AtomicInteger completionCounter = new AtomicInteger(groups.size());
    final AtomicReferenceArray<ShardActionResult> shardsResponses =
        new AtomicReferenceArray<>(groups.size());

    for (final ShardIterator shardIt : groups) {
      ShardRequest shardRequest = newShardRequestInstance(request, shardIt.shardId().id());

      // TODO for now, we fork operations on shardIt of the index
      shardRequest.beforeLocalFork(); // optimize for local fork
      shardRequest.operationThreaded(true);

      // no need for threaded listener, we will fork when its done based on the index request
      shardRequest.listenerThreaded(false);
      shardAction.execute(
          shardRequest,
          new ActionListener<ShardResponse>() {
            @Override
            public void onResponse(ShardResponse result) {
              shardsResponses.set(indexCounter.getAndIncrement(), new ShardActionResult(result));
              returnIfNeeded();
            }

            @Override
            public void onFailure(Throwable e) {
              failureCounter.getAndIncrement();
              int index = indexCounter.getAndIncrement();
              if (accumulateExceptions()) {
                shardsResponses.set(
                    index,
                    new ShardActionResult(
                        new DefaultShardOperationFailedException(
                            request.index, shardIt.shardId().id(), e)));
              }
              returnIfNeeded();
            }

            private void returnIfNeeded() {
              if (completionCounter.decrementAndGet() == 0) {
                List<ShardResponse> responses = Lists.newArrayList();
                List<ShardOperationFailedException> failures = Lists.newArrayList();
                for (int i = 0; i < shardsResponses.length(); i++) {
                  ShardActionResult shardActionResult = shardsResponses.get(i);
                  if (shardActionResult == null) {
                    assert !accumulateExceptions();
                    continue;
                  }
                  if (shardActionResult.isFailure()) {
                    assert accumulateExceptions() && shardActionResult.shardFailure != null;
                    failures.add(shardActionResult.shardFailure);
                  } else {
                    responses.add(shardActionResult.shardResponse);
                  }
                }

                assert failures.size() == 0 || failures.size() == failureCounter.get();
                listener.onResponse(
                    newResponseInstance(request, responses, failureCounter.get(), failures));
              }
            }
          });
    }
  }
 @Override
 public IndicesOptions indicesOptions() {
   return request.indicesOptions();
 }