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();
  }
 ContextHandler getContextHandler(AsyncContextEvent event) {
   if (event != null) {
     Context context = ((Context) event.getServletContext());
     if (context != null) return context.getContextHandler();
   }
   return null;
 }
  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 ServletResponse getServletResponse(AsyncContextEvent event) {
   if (event != null && event.getSuppliedResponse() != null) return event.getSuppliedResponse();
   return _channel.getResponse();
 }
 protected void cancelTimeout(AsyncContextEvent event) {
   if (event != null) event.cancelTimeoutTask();
 }
 protected void scheduleTimeout(AsyncContextEvent event) {
   Scheduler scheduler = _channel.getScheduler();
   if (scheduler != null && _timeoutMs > 0)
     event.setTimeoutTask(scheduler.schedule(event, _timeoutMs, TimeUnit.MILLISECONDS));
 }
  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();
    }
  }