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