diff --git a/spring-web/src/main/java/org/springframework/web/context/request/async/StandardServletAsyncWebRequest.java b/spring-web/src/main/java/org/springframework/web/context/request/async/StandardServletAsyncWebRequest.java index aa48427b2ad6..e83f5f1d9fa9 100644 --- a/spring-web/src/main/java/org/springframework/web/context/request/async/StandardServletAsyncWebRequest.java +++ b/spring-web/src/main/java/org/springframework/web/context/request/async/StandardServletAsyncWebRequest.java @@ -241,11 +241,11 @@ public void setAsyncWebRequest(StandardServletAsyncWebRequest asyncWebRequest) { } @Override - public ServletOutputStream getOutputStream() { + public ServletOutputStream getOutputStream() throws IOException { if (this.outputStream == null) { Assert.notNull(this.asyncWebRequest, "Not initialized"); - this.outputStream = new LifecycleServletOutputStream( - (HttpServletResponse) getResponse(), this.asyncWebRequest); + ServletOutputStream delegate = getResponse().getOutputStream(); + this.outputStream = new LifecycleServletOutputStream(delegate, this); } return this.outputStream; } @@ -258,6 +258,46 @@ public PrintWriter getWriter() throws IOException { } return this.writer; } + + @Override + public void flushBuffer() throws IOException { + obtainLockAndCheckState(); + try { + getResponse().flushBuffer(); + } + catch (IOException ex) { + handleIOException(ex, "ServletResponse failed to flushBuffer"); + } + finally { + releaseLock(); + } + } + + private void obtainLockAndCheckState() throws AsyncRequestNotUsableException { + Assert.notNull(this.asyncWebRequest, "Not initialized"); + if (this.asyncWebRequest.state != State.NEW) { + this.asyncWebRequest.stateLock.lock(); + if (this.asyncWebRequest.state != State.ASYNC) { + this.asyncWebRequest.stateLock.unlock(); + throw new AsyncRequestNotUsableException("Response not usable after " + + (this.asyncWebRequest.state == State.COMPLETED ? + "async request completion" : "onError notification") + "."); + } + } + } + + void handleIOException(IOException ex, String msg) throws AsyncRequestNotUsableException { + Assert.notNull(this.asyncWebRequest, "Not initialized"); + this.asyncWebRequest.transitionToErrorState(); + throw new AsyncRequestNotUsableException(msg, ex); + } + + void releaseLock() { + Assert.notNull(this.asyncWebRequest, "Not initialized"); + if (this.asyncWebRequest.state != State.NEW) { + this.asyncWebRequest.stateLock.unlock(); + } + } } @@ -267,113 +307,80 @@ public PrintWriter getWriter() throws IOException { */ private static final class LifecycleServletOutputStream extends ServletOutputStream { - private final HttpServletResponse delegate; - - private final StandardServletAsyncWebRequest asyncWebRequest; + private final ServletOutputStream delegate; - private LifecycleServletOutputStream( - HttpServletResponse delegate, StandardServletAsyncWebRequest asyncWebRequest) { + private final LifecycleHttpServletResponse response; + private LifecycleServletOutputStream(ServletOutputStream delegate, LifecycleHttpServletResponse response) { this.delegate = delegate; - this.asyncWebRequest = asyncWebRequest; + this.response = response; } @Override public boolean isReady() { - return false; + return this.delegate.isReady(); } @Override public void setWriteListener(WriteListener writeListener) { - throw new UnsupportedOperationException(); + this.delegate.setWriteListener(writeListener); } @Override public void write(int b) throws IOException { - obtainLockAndCheckState(); + this.response.obtainLockAndCheckState(); try { - this.delegate.getOutputStream().write(b); + this.delegate.write(b); } catch (IOException ex) { - handleIOException(ex, "ServletOutputStream failed to write"); + this.response.handleIOException(ex, "ServletOutputStream failed to write"); } finally { - releaseLock(); + this.response.releaseLock(); } } public void write(byte[] buf, int offset, int len) throws IOException { - obtainLockAndCheckState(); + this.response.obtainLockAndCheckState(); try { - this.delegate.getOutputStream().write(buf, offset, len); + this.delegate.write(buf, offset, len); } catch (IOException ex) { - handleIOException(ex, "ServletOutputStream failed to write"); + this.response.handleIOException(ex, "ServletOutputStream failed to write"); } finally { - releaseLock(); + this.response.releaseLock(); } } @Override public void flush() throws IOException { - obtainLockAndCheckState(); + this.response.obtainLockAndCheckState(); try { - this.delegate.getOutputStream().flush(); + this.delegate.flush(); } catch (IOException ex) { - handleIOException(ex, "ServletOutputStream failed to flush"); + this.response.handleIOException(ex, "ServletOutputStream failed to flush"); } finally { - releaseLock(); + this.response.releaseLock(); } } @Override public void close() throws IOException { - obtainLockAndCheckState(); + this.response.obtainLockAndCheckState(); try { - this.delegate.getOutputStream().close(); + this.delegate.close(); } catch (IOException ex) { - handleIOException(ex, "ServletOutputStream failed to close"); + this.response.handleIOException(ex, "ServletOutputStream failed to close"); } finally { - releaseLock(); - } - } - - private void obtainLockAndCheckState() throws AsyncRequestNotUsableException { - if (state() != State.NEW) { - stateLock().lock(); - if (state() != State.ASYNC) { - stateLock().unlock(); - throw new AsyncRequestNotUsableException("Response not usable after " + - (state() == State.COMPLETED ? - "async request completion" : "onError notification") + "."); - } + this.response.releaseLock(); } } - private void handleIOException(IOException ex, String msg) throws AsyncRequestNotUsableException { - this.asyncWebRequest.transitionToErrorState(); - throw new AsyncRequestNotUsableException(msg, ex); - } - - private void releaseLock() { - if (state() != State.NEW) { - stateLock().unlock(); - } - } - - private State state() { - return this.asyncWebRequest.state; - } - - private Lock stateLock() { - return this.asyncWebRequest.stateLock; - } - } diff --git a/spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncManager.java b/spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncManager.java index 59661bde9880..d4f0dfe3fa7b 100644 --- a/spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncManager.java +++ b/spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncManager.java @@ -488,14 +488,11 @@ private void startAsyncProcessing(Object[] processingContext) { } this.asyncWebRequest.startAsync(); - if (logger.isDebugEnabled()) { - logger.debug("Started async request"); - } } private static String formatUri(AsyncWebRequest asyncWebRequest) { HttpServletRequest request = asyncWebRequest.getNativeRequest(HttpServletRequest.class); - return (request != null ? request.getRequestURI() : "servlet container"); + return (request != null ? "\"" + request.getRequestURI() + "\"" : "servlet container"); }