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(); } }