public ContextHandler getContextHandler() {
   final AsyncContextEvent event;
   try (Locker.Lock lock = _locker.lock()) {
     event = _event;
   }
   return getContextHandler(event);
 }
 public ServletResponse getServletResponse() {
   final AsyncContextEvent event;
   try (Locker.Lock lock = _locker.lock()) {
     event = _event;
   }
   return getServletResponse(event);
 }
  public void complete() {

    // just like resume, except don't set _dispatched=true;
    boolean handle = false;
    AsyncContextEvent event;
    try (Locker.Lock lock = _locker.lock()) {
      if (DEBUG) LOG.debug("complete {}", toStringLocked());

      boolean started = false;
      event = _event;

      switch (_async) {
        case STARTED:
          started = true;
          break;
        case EXPIRING:
        case ERRORING:
        case ERRORED:
          break;
        case COMPLETE:
          return;
        default:
          throw new IllegalStateException(this.getStatusStringLocked());
      }
      _async = Async.COMPLETE;

      if (started && _state == State.ASYNC_WAIT) {
        handle = true;
        _state = State.ASYNC_WOKEN;
      }
    }

    cancelTimeout(event);
    if (handle) runInContext(event, _channel);
  }
 protected void cancelTimeout() {
   final AsyncContextEvent event;
   try (Locker.Lock lock = _locker.lock()) {
     event = _event;
   }
   cancelTimeout(event);
 }
  public void errorComplete() {
    try (Locker.Lock lock = _locker.lock()) {
      if (DEBUG) LOG.debug("error complete {}", toStringLocked());

      _async = Async.COMPLETE;
      _event.setDispatchContext(null);
      _event.setDispatchPath(null);
    }

    cancelTimeout();
  }
  /**
   * Called to signal that content is now available to read. If the channel is in ASYNC_WAIT state
   * and unready (ie isReady() has returned false), then the state is changed to ASYNC_WOKEN and
   * true is returned.
   *
   * @return True IFF the channel was unready and in ASYNC_WAIT state
   */
  public boolean onReadPossible() {
    boolean woken = false;
    try (Locker.Lock lock = _locker.lock()) {
      if (DEBUG) LOG.debug("onReadPossible {}", toStringLocked());

      _asyncReadPossible = true;
      if (_state == State.ASYNC_WAIT && _asyncReadUnready) {
        woken = true;
        _state = State.ASYNC_WOKEN;
      }
    }
    return woken;
  }
  public boolean onWritePossible() {
    boolean handle = false;

    try (Locker.Lock lock = _locker.lock()) {
      if (DEBUG) LOG.debug("onWritePossible {}", toStringLocked());

      _asyncWrite = true;
      if (_state == State.ASYNC_WAIT) {
        _state = State.ASYNC_WOKEN;
        handle = true;
      }
    }

    return handle;
  }
  /**
   * Called to signal async read isReady() has returned false. This indicates that there is no
   * content available to be consumed and that once the channel enteres the ASYNC_WAIT state it will
   * register for read interest by calling {@link HttpChannel#asyncReadFillInterested()} either from
   * this method or from a subsequent call to {@link #unhandle()}.
   */
  public void onReadUnready() {
    boolean interested = false;
    try (Locker.Lock lock = _locker.lock()) {
      if (DEBUG) LOG.debug("onReadUnready {}", toStringLocked());

      // We were already unready, this is not a state change, so do nothing
      if (!_asyncReadUnready) {
        _asyncReadUnready = true;
        _asyncReadPossible = false; // Assumes this has been checked in isReady() with lock held
        if (_state == State.ASYNC_WAIT) interested = true;
      }
    }

    if (interested) _channel.asyncReadFillInterested();
  }
  protected void onComplete() {
    final List<AsyncListener> aListeners;
    final AsyncContextEvent event;

    try (Locker.Lock lock = _locker.lock()) {
      if (DEBUG) LOG.debug("onComplete {}", toStringLocked());

      switch (_state) {
        case COMPLETING:
          aListeners = _asyncListeners;
          event = _event;
          _state = State.COMPLETED;
          _async = null;
          break;

        default:
          throw new IllegalStateException(this.getStatusStringLocked());
      }
    }

    if (event != null) {
      if (aListeners != null) {
        Runnable callback =
            new Runnable() {
              @Override
              public void run() {
                for (AsyncListener listener : aListeners) {
                  try {
                    listener.onComplete(event);
                  } catch (Exception e) {
                    LOG.warn(e + " while invoking onComplete listener " + listener);
                    LOG.debug(e);
                  }
                }
              }

              @Override
              public String toString() {
                return "onComplete";
              }
            };

        runInContext(event, callback);
      }
      event.completed();
    }
  }
  public void dispatch(ServletContext context, String path) {
    boolean dispatch = false;
    AsyncContextEvent event;
    try (Locker.Lock lock = _locker.lock()) {
      if (DEBUG) LOG.debug("dispatch {} -> {}", toStringLocked(), path);

      boolean started = false;
      event = _event;
      switch (_async) {
        case STARTED:
          started = true;
          break;
        case EXPIRING:
        case ERRORING:
        case ERRORED:
          break;
        default:
          throw new IllegalStateException(this.getStatusStringLocked());
      }
      _async = Async.DISPATCH;

      if (context != null) _event.setDispatchContext(context);
      if (path != null) _event.setDispatchPath(path);

      if (started) {
        switch (_state) {
          case DISPATCHED:
          case ASYNC_IO:
          case ASYNC_WOKEN:
            break;
          case ASYNC_WAIT:
            _state = State.ASYNC_WOKEN;
            dispatch = true;
            break;
          default:
            LOG.warn("async dispatched when complete {}", this);
            break;
        }
      }
    }

    cancelTimeout(event);
    if (dispatch) scheduleDispatch();
  }
  public void upgrade() {
    cancelTimeout();
    try (Locker.Lock lock = _locker.lock()) {
      if (DEBUG) LOG.debug("upgrade {}", toStringLocked());

      switch (_state) {
        case IDLE:
        case COMPLETED:
          break;
        default:
          throw new IllegalStateException(getStatusStringLocked());
      }
      _asyncListeners = null;
      _state = State.UPGRADED;
      _async = null;
      _initial = true;
      _asyncReadPossible = _asyncReadUnready = false;
      _asyncWrite = false;
      _timeoutMs = DEFAULT_TIMEOUT;
      _event = null;
    }
  }
  public void startAsync(AsyncContextEvent event) {
    final List<AsyncListener> lastAsyncListeners;

    try (Locker.Lock lock = _locker.lock()) {
      if (DEBUG) LOG.debug("startAsync {}", toStringLocked());

      if (_state != State.DISPATCHED || _async != null)
        throw new IllegalStateException(this.getStatusStringLocked());

      _async = Async.STARTED;
      _event = event;
      lastAsyncListeners = _asyncListeners;
      _asyncListeners = null;
    }

    if (lastAsyncListeners != null) {
      Runnable callback =
          new Runnable() {
            @Override
            public void run() {
              for (AsyncListener listener : lastAsyncListeners) {
                try {
                  listener.onStartAsync(event);
                } catch (Exception e) {
                  // TODO Async Dispatch Error
                  LOG.warn(e);
                }
              }
            }

            @Override
            public String toString() {
              return "startAsync";
            }
          };

      runInContext(event, callback);
    }
  }
  protected void recycle() {
    cancelTimeout();
    try (Locker.Lock lock = _locker.lock()) {
      if (DEBUG) LOG.debug("recycle {}", toStringLocked());

      switch (_state) {
        case DISPATCHED:
        case ASYNC_IO:
          throw new IllegalStateException(getStatusStringLocked());
        case UPGRADED:
          return;
        default:
          break;
      }
      _asyncListeners = null;
      _state = State.IDLE;
      _async = null;
      _initial = true;
      _asyncReadPossible = _asyncReadUnready = false;
      _asyncWrite = false;
      _timeoutMs = DEFAULT_TIMEOUT;
      _event = null;
    }
  }
 boolean isCompleted() {
   try (Locker.Lock lock = _locker.lock()) {
     return _state == State.COMPLETED;
   }
 }
 boolean isCompleting() {
   try (Locker.Lock lock = _locker.lock()) {
     return _state == State.COMPLETING;
   }
 }
 public boolean isSuspended() {
   try (Locker.Lock lock = _locker.lock()) {
     return _state == State.ASYNC_WAIT || _state == State.DISPATCHED && _async == Async.STARTED;
   }
 }
  protected void onTimeout() {
    final List<AsyncListener> listeners;
    AsyncContextEvent event;
    try (Locker.Lock lock = _locker.lock()) {
      if (DEBUG) LOG.debug("onTimeout {}", toStringLocked());

      if (_async != Async.STARTED) return;
      _async = Async.EXPIRING;
      event = _event;
      listeners = _asyncListeners;
    }

    final AtomicReference<Throwable> error = new AtomicReference<Throwable>();
    if (listeners != null) {
      Runnable task =
          new Runnable() {
            @Override
            public void run() {
              for (AsyncListener listener : listeners) {
                try {
                  listener.onTimeout(event);
                } catch (Throwable x) {
                  LOG.warn(x + " while invoking onTimeout listener " + listener);
                  LOG.debug(x);
                  if (error.get() == null) error.set(x);
                  else error.get().addSuppressed(x);
                }
              }
            }

            @Override
            public String toString() {
              return "onTimeout";
            }
          };

      runInContext(event, task);
    }

    Throwable th = error.get();
    boolean dispatch = false;
    try (Locker.Lock lock = _locker.lock()) {
      switch (_async) {
        case EXPIRING:
          _async = th == null ? Async.EXPIRED : Async.ERRORING;
          break;

        case COMPLETE:
        case DISPATCH:
          if (th != null) {
            LOG.ignore(th);
            th = null;
          }
          break;

        default:
          throw new IllegalStateException();
      }

      if (_state == State.ASYNC_WAIT) {
        _state = State.ASYNC_WOKEN;
        dispatch = true;
      }
    }

    if (th != null) {
      if (LOG.isDebugEnabled()) LOG.debug("Error after async timeout {}", this, th);
      onError(th);
    }

    if (dispatch) {
      if (LOG.isDebugEnabled()) LOG.debug("Dispatch after async timeout {}", this);
      scheduleDispatch();
    }
  }
 public boolean isReadPossible() {
   try (Locker.Lock lock = _locker.lock()) {
     return _asyncReadPossible;
   }
 }
  /** @return Next handling of the request should proceed */
  protected Action handling() {
    try (Locker.Lock lock = _locker.lock()) {
      if (DEBUG) LOG.debug("handling {}", toStringLocked());

      switch (_state) {
        case IDLE:
          _initial = true;
          _state = State.DISPATCHED;
          return Action.DISPATCH;

        case COMPLETING:
          return Action.COMPLETE;

        case COMPLETED:
          return Action.TERMINATED;

        case ASYNC_WOKEN:
          if (_asyncReadPossible) {
            _state = State.ASYNC_IO;
            _asyncReadUnready = false;
            return Action.READ_CALLBACK;
          }

          if (_asyncWrite) {
            _state = State.ASYNC_IO;
            _asyncWrite = false;
            return Action.WRITE_CALLBACK;
          }

          if (_async != null) {
            Async async = _async;
            switch (async) {
              case COMPLETE:
                _state = State.COMPLETING;
                return Action.COMPLETE;
              case DISPATCH:
                _state = State.DISPATCHED;
                _async = null;
                return Action.ASYNC_DISPATCH;
              case EXPIRED:
              case ERRORED:
                _state = State.DISPATCHED;
                _async = null;
                return Action.ERROR_DISPATCH;
              case STARTED:
              case EXPIRING:
              case ERRORING:
                return Action.WAIT;

              default:
                throw new IllegalStateException(getStatusStringLocked());
            }
          }

          return Action.WAIT;

        case ASYNC_IO:
        case ASYNC_WAIT:
        case DISPATCHED:
        case UPGRADED:
        default:
          throw new IllegalStateException(getStatusStringLocked());
      }
    }
  }
  protected void onError(Throwable failure) {
    final List<AsyncListener> listeners;
    final AsyncContextEvent event;
    final Request baseRequest = _channel.getRequest();

    int code = HttpStatus.INTERNAL_SERVER_ERROR_500;
    String reason = null;
    if (failure instanceof BadMessageException) {
      BadMessageException bme = (BadMessageException) failure;
      code = bme.getCode();
      reason = bme.getReason();
    } else if (failure instanceof UnavailableException) {
      if (((UnavailableException) failure).isPermanent()) code = HttpStatus.NOT_FOUND_404;
      else code = HttpStatus.SERVICE_UNAVAILABLE_503;
    }

    try (Locker.Lock lock = _locker.lock()) {
      if (DEBUG) LOG.debug("onError {} {}", toStringLocked(), failure);

      // Set error on request.
      if (_event != null) {
        if (_event.getThrowable() != null)
          throw new IllegalStateException("Error already set", _event.getThrowable());
        _event.addThrowable(failure);
        _event.getSuppliedRequest().setAttribute(ERROR_STATUS_CODE, code);
        _event.getSuppliedRequest().setAttribute(ERROR_EXCEPTION, failure);
        _event
            .getSuppliedRequest()
            .setAttribute(
                RequestDispatcher.ERROR_EXCEPTION_TYPE,
                failure == null ? null : failure.getClass());

        _event.getSuppliedRequest().setAttribute(ERROR_MESSAGE, reason != null ? reason : null);
      } else {
        Throwable error = (Throwable) baseRequest.getAttribute(ERROR_EXCEPTION);
        if (error != null) throw new IllegalStateException("Error already set", error);
        baseRequest.setAttribute(ERROR_STATUS_CODE, code);
        baseRequest.setAttribute(ERROR_EXCEPTION, failure);
        baseRequest.setAttribute(
            RequestDispatcher.ERROR_EXCEPTION_TYPE, failure == null ? null : failure.getClass());
        baseRequest.setAttribute(ERROR_MESSAGE, reason != null ? reason : null);
      }

      // Are we blocking?
      if (_async == null) {
        // Only called from within HttpChannel Handling, so much be dispatched, let's stay
        // dispatched!
        if (_state == State.DISPATCHED) {
          _state = State.THROWN;
          return;
        }
        throw new IllegalStateException(this.getStatusStringLocked());
      }

      // We are Async
      _async = Async.ERRORING;
      listeners = _asyncListeners;
      event = _event;
    }

    if (listeners != null) {
      Runnable task =
          new Runnable() {
            @Override
            public void run() {
              for (AsyncListener listener : listeners) {
                try {
                  listener.onError(event);
                } catch (Throwable x) {
                  LOG.warn(x + " while invoking onError listener " + listener);
                  LOG.debug(x);
                }
              }
            }

            @Override
            public String toString() {
              return "onError";
            }
          };
      runInContext(event, task);
    }

    boolean dispatch = false;
    try (Locker.Lock lock = _locker.lock()) {
      switch (_async) {
        case ERRORING:
          {
            // Still in this state ? The listeners did not invoke API methods
            // and the container must provide a default error dispatch.
            _async = Async.ERRORED;
            break;
          }
        case DISPATCH:
        case COMPLETE:
          {
            // The listeners called dispatch() or complete().
            break;
          }
        default:
          {
            throw new IllegalStateException(toString());
          }
      }

      if (_state == State.ASYNC_WAIT) {
        _state = State.ASYNC_WOKEN;
        dispatch = true;
      }
    }

    if (dispatch) {
      if (LOG.isDebugEnabled()) LOG.debug("Dispatch after error {}", this);
      scheduleDispatch();
    }
  }
  /**
   * Signal that the HttpConnection has finished handling the request. For blocking connectors,this
   * call may block if the request has been suspended (startAsync called).
   *
   * @return next actions be handled again (eg because of a resume that happened before unhandle was
   *     called)
   */
  protected Action unhandle() {
    Action action;
    AsyncContextEvent schedule_event = null;
    boolean read_interested = false;

    try (Locker.Lock lock = _locker.lock()) {
      if (DEBUG) LOG.debug("unhandle {}", toStringLocked());

      switch (_state) {
        case COMPLETING:
        case COMPLETED:
          return Action.TERMINATED;

        case THROWN:
          _state = State.DISPATCHED;
          return Action.ERROR_DISPATCH;

        case DISPATCHED:
        case ASYNC_IO:
          break;

        default:
          throw new IllegalStateException(this.getStatusStringLocked());
      }

      if (_async != null) {
        _initial = false;
        switch (_async) {
          case COMPLETE:
            _state = State.COMPLETING;
            _async = null;
            action = Action.COMPLETE;
            break;

          case DISPATCH:
            _state = State.DISPATCHED;
            _async = null;
            action = Action.ASYNC_DISPATCH;
            break;

          case STARTED:
            if (_asyncReadUnready && _asyncReadPossible) {
              _state = State.ASYNC_IO;
              _asyncReadUnready = false;
              action = Action.READ_CALLBACK;
            } else if (_asyncWrite) // TODO refactor same as read
            {
              _asyncWrite = false;
              _state = State.ASYNC_IO;
              action = Action.WRITE_CALLBACK;
            } else {
              schedule_event = _event;
              read_interested = _asyncReadUnready;
              _state = State.ASYNC_WAIT;
              action = Action.WAIT;
            }
            break;

          case EXPIRING:
            // onTimeout callbacks still being called, so just WAIT
            _state = State.ASYNC_WAIT;
            action = Action.WAIT;
            break;

          case EXPIRED:
            // onTimeout handling is complete, but did not dispatch as
            // we were handling.  So do the error dispatch here
            _state = State.DISPATCHED;
            _async = null;
            action = Action.ERROR_DISPATCH;
            break;

          case ERRORED:
            _state = State.DISPATCHED;
            _async = null;
            action = Action.ERROR_DISPATCH;
            break;

          default:
            throw new IllegalStateException(this.getStatusStringLocked());
        }
      } else {
        _state = State.COMPLETING;
        action = Action.COMPLETE;
      }
    }

    if (schedule_event != null) scheduleTimeout(schedule_event);
    if (read_interested) _channel.asyncReadFillInterested();
    return action;
  }
 public boolean isAsyncStarted() {
   try (Locker.Lock lock = _locker.lock()) {
     if (_state == State.DISPATCHED) return _async != null;
     return _async == Async.STARTED || _async == Async.EXPIRING;
   }
 }
 public boolean isAsync() {
   try (Locker.Lock lock = _locker.lock()) {
     return !_initial || _async != null;
   }
 }
 public AsyncContextEvent getAsyncContextEvent() {
   try (Locker.Lock lock = _locker.lock()) {
     return _event;
   }
 }
 public String getStatusString() {
   try (Locker.Lock lock = _locker.lock()) {
     return getStatusStringLocked();
   }
 }
 public boolean isIdle() {
   try (Locker.Lock lock = _locker.lock()) {
     return _state == State.IDLE;
   }
 }
 @Override
 public String toString() {
   try (Locker.Lock lock = _locker.lock()) {
     return toStringLocked();
   }
 }
 public boolean isExpired() {
   try (Locker.Lock lock = _locker.lock()) {
     return _async == Async.EXPIRED;
   }
 }
 public long getTimeout() {
   try (Locker.Lock lock = _locker.lock()) {
     return _timeoutMs;
   }
 }
 public boolean isInitial() {
   try (Locker.Lock lock = _locker.lock()) {
     return _initial;
   }
 }