public void open(ExecutionContext executionContext) throws ItemStreamException {
   if (executionContext.containsKey(EXPECTED)) {
     localState.expected = executionContext.getLong(EXPECTED);
     localState.actual = executionContext.getLong(ACTUAL);
     if (!waitForResults()) {
       throw new ItemStreamException("Timed out waiting for back log on open");
     }
   }
 }
 /**
  * Wait until all the results that are in the pipeline come back to the reply channel.
  *
  * @return true if successfully received a result, false if timed out
  */
 private boolean waitForResults() {
   int count = 0;
   int maxCount = maxWaitTimeouts;
   while (localState.getExpecting() > 0 && count++ < maxCount) {
     long expecting = localState.getExpecting();
     getNextResult();
     if (expecting == localState.getExpecting()) {
       try {
         Thread.sleep(100);
       } catch (InterruptedException e) {
         throw new RuntimeException(e);
       }
     }
   }
   return count < maxCount;
 }
  public void write(List<? extends T> items) throws Exception {

    // Block until expecting <= throttle limit
    while (localState.getExpecting() > throttleLimit) {
      getNextResult();
    }

    if (!items.isEmpty()) {
      logger.debug("Dispatching chunk: " + items);
      ChunkRequest<T> request =
          new ChunkRequest<T>(items, localState.getJobId(), localState.createStepContribution());

      // Create & launch task
      ChunkTask<T> task = new ChunkTask<T>();
      task.setProcessor(chunkProcessor);
      GridTaskFuture<ChunkResponse> future =
          grid.<ChunkRequest<T>, ChunkResponse>execute(task, request);
      futures.add(future);

      localState.expected++;
    }
  }
  /**
   * Get the next result if it is available (within the timeout specified in the gateway), otherwise
   * do nothing.
   *
   * @throws AsynchronousFailureException If there is a response and it contains a failed chunk
   *     response.
   * @throws IllegalStateException if the result contains the wrong job instance id (maybe we are
   *     sharing a channel and we shouldn't be)
   */
  private void getNextResult() {
    ChunkResponse payload = null;

    // Retrieve first finished task found
    Iterator<GridTaskFuture<ChunkResponse>> iterator = futures.iterator();
    while (iterator.hasNext()) {
      GridTaskFuture<ChunkResponse> future = iterator.next();
      if (future.isDone()) {
        try {
          payload = future.get();
        } catch (GridException e) {
          throw new AsynchronousFailureException(
              "Exception occured during GridGain task execution: " + e);
        }
        iterator.remove();
        break;
      }
    }

    if (payload != null) {
      Long jobInstanceId = payload.getJobId();
      Assert.state(jobInstanceId != null, "Message did not contain job instance id.");
      Assert.state(
          jobInstanceId.equals(localState.getJobId()),
          "Message contained wrong job instance id ["
              + jobInstanceId
              + "] should have been ["
              + localState.getJobId()
              + "].");
      localState.actual++;
      // TODO: apply the skip count
      if (!payload.isSuccessful()) {
        throw new AsynchronousFailureException(
            "Failure or interrupt detected in handler: " + payload.getMessage());
      }
    }
  }
 @Override
 public ExitStatus afterStep(StepExecution stepExecution) {
   if (!(stepExecution.getStatus() == BatchStatus.COMPLETED)) {
     return ExitStatus.EXECUTING;
   }
   long expecting = localState.getExpecting();
   boolean timedOut;
   try {
     logger.debug("Waiting for results in step listener...");
     timedOut = !waitForResults();
     logger.debug("Finished waiting for results in step listener.");
   } catch (RuntimeException e) {
     logger.debug("Detected failure waiting for results in step listener.", e);
     stepExecution.setStatus(BatchStatus.FAILED);
     return ExitStatus.FAILED.addExitDescription(e.getClass().getName() + ": " + e.getMessage());
   }
   if (timedOut) {
     stepExecution.setStatus(BatchStatus.FAILED);
     throw new ItemStreamException("Timed out waiting for back log at end of step");
   }
   return ExitStatus.COMPLETED.addExitDescription("Waited for " + expecting + " results.");
 }
 @Override
 public void beforeStep(StepExecution stepExecution) {
   localState.setStepExecution(stepExecution);
   futures = new ArrayList<GridTaskFuture<ChunkResponse>>();
 }
 public void close() throws ItemStreamException {
   localState.reset();
 }