@Override
 public void rst(RstInfo rstInfo)
     throws InterruptedException, ExecutionException, TimeoutException {
   FutureCallback result = new FutureCallback();
   rst(rstInfo, result);
   if (rstInfo.getTimeout() > 0) result.get(rstInfo.getTimeout(), rstInfo.getUnit());
   else result.get();
 }
 private void onHeaders(HeadersFrame frame) {
   int streamId = frame.getStreamId();
   IStream stream = streams.get(streamId);
   if (stream == null) {
     RstInfo rstInfo = new RstInfo(streamId, StreamStatus.INVALID_STREAM);
     LOG.debug("Unknown stream, {}", rstInfo);
     rst(rstInfo, new Callback.Adapter());
   } else {
     processHeaders(stream, frame);
   }
 }
  private IStream createStream(
      SynStreamFrame frame, StreamFrameListener listener, boolean local, Promise<Stream> promise) {
    IStream associatedStream = streams.get(frame.getAssociatedStreamId());
    IStream stream =
        new StandardStream(
            frame.getStreamId(), frame.getPriority(), this, associatedStream, promise);
    flowControlStrategy.onNewStream(this, stream);

    stream.updateCloseState(frame.isClose(), local);
    stream.setStreamFrameListener(listener);

    if (stream.isUnidirectional()) {
      // Unidirectional streams are implicitly half closed
      stream.updateCloseState(true, !local);
      if (!stream.isClosed()) stream.getAssociatedStream().associate(stream);
    }

    int streamId = stream.getId();

    if (local) {
      while (true) {
        int oldStreamCountValue = localStreamCount.get();
        int maxConcurrentStreams = maxConcurrentLocalStreams;
        if (maxConcurrentStreams > -1 && oldStreamCountValue >= maxConcurrentStreams) {
          String message =
              String.format("Max concurrent local streams (%d) exceeded.", maxConcurrentStreams);
          LOG.debug(message);
          promise.failed(new SPDYException(message));
          return null;
        }
        if (localStreamCount.compareAndSet(oldStreamCountValue, oldStreamCountValue + 1)) break;
      }
    }

    if (streams.putIfAbsent(streamId, stream) != null) {
      String message = "Duplicate stream id " + streamId;
      IllegalStateException duplicateIdException = new IllegalStateException(message);
      promise.failed(duplicateIdException);
      if (local) {
        localStreamCount.decrementAndGet();
        throw duplicateIdException;
      }
      RstInfo rstInfo = new RstInfo(streamId, StreamStatus.PROTOCOL_ERROR);
      LOG.debug("Duplicate stream, {}", rstInfo);
      rst(rstInfo, new Callback.Adapter()); // We don't care (too much) if the reset fails.
      return null;
    } else {
      LOG.debug("Created {}", stream);
      notifyStreamCreated(stream);
      return stream;
    }
  }
  @Override
  public void onDataFrame(DataFrame frame, ByteBuffer data) {
    notifyIdle(idleListener, false);
    try {
      LOG.debug("Processing {}, {} data bytes", frame, data.remaining());

      if (goAwaySent.get()) {
        LOG.debug("Skipped processing of {}", frame);
        return;
      }

      int streamId = frame.getStreamId();
      IStream stream = streams.get(streamId);
      if (stream == null) {
        RstInfo rstInfo = new RstInfo(streamId, StreamStatus.INVALID_STREAM);
        LOG.debug("Unknown stream {}", rstInfo);
        rst(rstInfo, new Callback.Adapter());
      } else {
        processData(stream, frame, data);
      }
    } finally {
      notifyIdle(idleListener, true);
    }
  }
 @Override
 public void onStreamException(StreamException x) {
   notifyOnException(listener, x);
   rst(new RstInfo(x.getStreamId(), x.getStreamStatus()), new Callback.Adapter());
 }