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