diff --git a/spring-web/src/main/java/org/springframework/http/server/ServerHttpAsyncResponseControl.java b/spring-web/src/main/java/org/springframework/http/server/ServerHttpAsyncRequestControl.java similarity index 95% rename from spring-web/src/main/java/org/springframework/http/server/ServerHttpAsyncResponseControl.java rename to spring-web/src/main/java/org/springframework/http/server/ServerHttpAsyncRequestControl.java index 55120c5c754..79dfd55c3bc 100644 --- a/spring-web/src/main/java/org/springframework/http/server/ServerHttpAsyncResponseControl.java +++ b/spring-web/src/main/java/org/springframework/http/server/ServerHttpAsyncRequestControl.java @@ -23,7 +23,7 @@ package org.springframework.http.server; * @author Rossen Stoyanchev * @since 4.0 */ -public interface ServerHttpAsyncResponseControl { +public interface ServerHttpAsyncRequestControl { /** * Enable asynchronous processing after which the response remains open until a call @@ -42,7 +42,7 @@ public interface ServerHttpAsyncResponseControl { /** * Whether asynchronous request processing has been started. */ - boolean hasStarted(); + boolean isStarted(); /** * Causes asynchronous request processing to be completed. diff --git a/spring-web/src/main/java/org/springframework/http/server/ServerHttpRequest.java b/spring-web/src/main/java/org/springframework/http/server/ServerHttpRequest.java index 8e6a5647e22..7321d071048 100644 --- a/spring-web/src/main/java/org/springframework/http/server/ServerHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/server/ServerHttpRequest.java @@ -28,6 +28,7 @@ import org.springframework.util.MultiValueMap; * Represents a server-side HTTP request. * * @author Arjen Poutsma + * @author Rossen Stoyanchev * @since 3.0 */ public interface ServerHttpRequest extends HttpRequest, HttpInputMessage { @@ -39,7 +40,6 @@ public interface ServerHttpRequest extends HttpRequest, HttpInputMessage { /** * Return the cookie values parsed from the "Cookie" request header. - * @return the cookies */ Map getCookies(); @@ -60,4 +60,10 @@ public interface ServerHttpRequest extends HttpRequest, HttpInputMessage { */ String getRemoteAddress(); + /** + * Return a control that allows putting the request in asynchronous mode so the + * response remains open until closed explicitly from the current or another thread. + */ + ServerHttpAsyncRequestControl getAsyncRequestControl(ServerHttpResponse response); + } diff --git a/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpAsyncRequestControl.java b/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpAsyncRequestControl.java index 5cc5b8dd401..f7f0b91d95d 100644 --- a/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpAsyncRequestControl.java +++ b/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpAsyncRequestControl.java @@ -29,12 +29,12 @@ import org.springframework.util.Assert; /** - * A {@link ServerHttpAsyncResponseControl} to use on Servlet containers (Servlet 3.0+). + * A {@link ServerHttpAsyncRequestControl} to use on Servlet containers (Servlet 3.0+). * * @author Rossen Stoyanchev * @since 4.0 */ -public class ServletServerHttpAsyncRequestControl implements ServerHttpAsyncResponseControl, AsyncListener { +public class ServletServerHttpAsyncRequestControl implements ServerHttpAsyncRequestControl, AsyncListener { private static long NO_TIMEOUT_VALUE = Long.MIN_VALUE; @@ -52,27 +52,24 @@ public class ServletServerHttpAsyncRequestControl implements ServerHttpAsyncResp * {@link ServletServerHttpRequest} and {@link ServletServerHttpResponse} * respectively. */ - public ServletServerHttpAsyncRequestControl(ServerHttpRequest request, ServerHttpResponse response) { + public ServletServerHttpAsyncRequestControl(ServletServerHttpRequest request, ServletServerHttpResponse response) { Assert.notNull(request, "request is required"); Assert.notNull(response, "response is required"); - Assert.isInstanceOf(ServletServerHttpRequest.class, request); - Assert.isInstanceOf(ServletServerHttpResponse.class, response); - - this.request = (ServletServerHttpRequest) request; - this.response = (ServletServerHttpResponse) response; - - Assert.isTrue(this.request.getServletRequest().isAsyncSupported(), + Assert.isTrue(request.getServletRequest().isAsyncSupported(), "Async support must be enabled on a servlet and for all filters involved " + "in async request processing. This is done in Java code using the Servlet API " + "or by adding \"true\" to servlet and " + "filter declarations in web.xml. Also you must use a Servlet 3.0+ container"); + + this.request = request; + this.response = response; } @Override - public boolean hasStarted() { + public boolean isStarted() { return ((this.asyncContext != null) && this.request.getServletRequest().isAsyncStarted()); } @@ -91,7 +88,7 @@ public class ServletServerHttpAsyncRequestControl implements ServerHttpAsyncResp Assert.state(!isCompleted(), "Async processing has already completed"); - if (hasStarted()) { + if (isStarted()) { return; } @@ -108,7 +105,7 @@ public class ServletServerHttpAsyncRequestControl implements ServerHttpAsyncResp @Override public void complete() { - if (hasStarted() && !isCompleted()) { + if (isStarted() && !isCompleted()) { this.asyncContext.complete(); } } diff --git a/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java b/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java index fa85df5a190..22a8720083e 100644 --- a/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java @@ -72,6 +72,7 @@ public class ServletServerHttpRequest implements ServerHttpRequest { private MultiValueMap queryParams; + private ServerHttpAsyncRequestControl asyncRequestControl; /** * Construct a new instance of the ServletServerHttpRequest based on the given {@link HttpServletRequest}. @@ -238,4 +239,14 @@ public class ServletServerHttpRequest implements ServerHttpRequest { return new ByteArrayInputStream(bos.toByteArray()); } + @Override + public ServerHttpAsyncRequestControl getAsyncRequestControl(ServerHttpResponse response) { + if (this.asyncRequestControl == null) { + Assert.isInstanceOf(ServletServerHttpResponse.class, response); + ServletServerHttpResponse servletServerResponse = (ServletServerHttpResponse) response; + this.asyncRequestControl = new ServletServerHttpAsyncRequestControl(this, servletServerResponse); + } + return this.asyncRequestControl; + } + } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/AbstractHttpSockJsSession.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/AbstractHttpSockJsSession.java index 0cca3c8a007..c9066187c77 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/AbstractHttpSockJsSession.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/transport/session/AbstractHttpSockJsSession.java @@ -20,10 +20,9 @@ import java.io.IOException; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; -import org.springframework.http.server.ServerHttpAsyncResponseControl; +import org.springframework.http.server.ServerHttpAsyncRequestControl; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; -import org.springframework.http.server.ServletServerHttpAsyncRequestControl; import org.springframework.util.Assert; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.WebSocketHandler; @@ -48,7 +47,7 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession { private ServerHttpResponse response; - private ServerHttpAsyncResponseControl asyncControl; + private ServerHttpAsyncRequestControl asyncRequestControl; private String protocol; @@ -109,7 +108,7 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession { return; } try { - this.asyncControl.start(-1); + this.asyncRequestControl.start(-1); scheduleHeartbeat(); tryFlushCache(); } @@ -125,14 +124,14 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession { Assert.notNull(frameFormat, "expected frameFormat"); this.request = request; this.response = response; - this.asyncControl = new ServletServerHttpAsyncRequestControl(this.request, this.response); + this.asyncRequestControl = request.getAsyncRequestControl(response); this.frameFormat = frameFormat; } @Override public synchronized boolean isActive() { - return ((this.asyncControl != null) && (!this.asyncControl.isCompleted())); + return ((this.asyncRequestControl != null) && (!this.asyncRequestControl.isCompleted())); } protected BlockingQueue getMessageCache() { @@ -172,10 +171,10 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession { protected synchronized void resetRequest() { updateLastActiveTime(); - if (isActive() && this.asyncControl.hasStarted()) { + if (isActive() && this.asyncRequestControl.isStarted()) { try { logger.debug("Completing asynchronous request"); - this.asyncControl.complete(); + this.asyncRequestControl.complete(); } catch (Throwable ex) { logger.error("Failed to complete request: " + ex.getMessage()); @@ -183,7 +182,7 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession { } this.request = null; this.response = null; - this.asyncControl = null; + this.asyncRequestControl = null; } @Override diff --git a/spring-websocket/src/test/java/org/springframework/web/socket/AbstractHttpRequestTests.java b/spring-websocket/src/test/java/org/springframework/web/socket/AbstractHttpRequestTests.java index 63bd10b46cf..10a2c051c60 100644 --- a/spring-websocket/src/test/java/org/springframework/web/socket/AbstractHttpRequestTests.java +++ b/spring-websocket/src/test/java/org/springframework/web/socket/AbstractHttpRequestTests.java @@ -17,10 +17,9 @@ package org.springframework.web.socket; import org.junit.Before; -import org.springframework.http.server.ServerHttpAsyncResponseControl; +import org.springframework.http.server.ServerHttpAsyncRequestControl; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; -import org.springframework.http.server.ServletServerHttpAsyncRequestControl; import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.http.server.ServletServerHttpResponse; import org.springframework.mock.web.test.MockHttpServletRequest; @@ -41,7 +40,7 @@ public class AbstractHttpRequestTests { protected MockHttpServletResponse servletResponse; - protected ServerHttpAsyncResponseControl asyncControl; + protected ServerHttpAsyncRequestControl asyncControl; @Before @@ -57,7 +56,7 @@ public class AbstractHttpRequestTests { protected void resetRequestAndResponse() { resetRequest(); resetResponse(); - this.asyncControl = new ServletServerHttpAsyncRequestControl(this.request, this.response); + this.asyncControl = this.request.getAsyncRequestControl(this.response); } protected void resetRequest() { diff --git a/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/support/AbstractSockJsServiceTests.java b/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/support/AbstractSockJsServiceTests.java index 8a859b29647..cdf9efe3b60 100644 --- a/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/support/AbstractSockJsServiceTests.java +++ b/spring-websocket/src/test/java/org/springframework/web/socket/sockjs/support/AbstractSockJsServiceTests.java @@ -246,7 +246,7 @@ public class AbstractSockJsServiceTests extends AbstractHttpRequestTests { @Override protected void handleTransportRequest(ServerHttpRequest req, ServerHttpResponse res, WebSocketHandler handler, - String sessionId, String transport) throws IOException, SockJsException { + String sessionId, String transport) throws SockJsException { this.sessionId = sessionId; this.transport = transport;