Polish async feature for ServerHttpRequest/Response
ServerHttpAsyncResponseControl wraps a ServetHttpRequest and -Response pair and allows putting the processing of the request in async mode so that the response remains open until explicitly closed, either from the current or from another thread. ServletServerHttpAsyncResponseControl provides a Serlvet-based implementation.
This commit is contained in:
@@ -22,9 +22,9 @@ import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.http.server.AsyncServletServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.http.server.ServletServerHttpRequest;
|
||||
import org.springframework.http.server.ServletServerHttpResponse;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.HttpRequestHandler;
|
||||
@@ -71,13 +71,13 @@ public class SockJsHttpRequestHandler implements HttpRequestHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
|
||||
public void handleRequest(HttpServletRequest servletRequest, HttpServletResponse servletResponse)
|
||||
throws ServletException, IOException {
|
||||
|
||||
ServerHttpRequest httpRequest = new AsyncServletServerHttpRequest(request, response);
|
||||
ServerHttpResponse httpResponse = new ServletServerHttpResponse(response);
|
||||
ServerHttpRequest serverRequest = new ServletServerHttpRequest(servletRequest);
|
||||
ServerHttpResponse serverResponse = new ServletServerHttpResponse(servletResponse);
|
||||
|
||||
this.sockJsService.handleRequest(httpRequest, httpResponse, this.webSocketHandler);
|
||||
this.sockJsService.handleRequest(serverRequest, serverResponse, this.webSocketHandler);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,15 +20,16 @@ import java.io.IOException;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
import org.springframework.http.server.AsyncServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpAsyncResponseControl;
|
||||
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;
|
||||
import org.springframework.web.socket.sockjs.SockJsProcessingException;
|
||||
import org.springframework.web.socket.sockjs.support.frame.SockJsFrame;
|
||||
import org.springframework.web.socket.sockjs.support.frame.SockJsFrame.FrameFormat;
|
||||
import org.springframework.web.socket.sockjs.SockJsProcessingException;
|
||||
import org.springframework.web.socket.support.ExceptionWebSocketHandlerDecorator;
|
||||
|
||||
/**
|
||||
@@ -43,10 +44,12 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession {
|
||||
|
||||
private final BlockingQueue<String> messageCache = new ArrayBlockingQueue<String>(100);
|
||||
|
||||
private AsyncServerHttpRequest asyncRequest;
|
||||
private ServerHttpRequest request;
|
||||
|
||||
private ServerHttpResponse response;
|
||||
|
||||
private ServerHttpAsyncResponseControl asyncControl;
|
||||
|
||||
private String protocol;
|
||||
|
||||
|
||||
@@ -113,8 +116,7 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession {
|
||||
return;
|
||||
}
|
||||
|
||||
this.asyncRequest.setTimeout(-1);
|
||||
this.asyncRequest.startAsync();
|
||||
this.asyncControl.start(-1);
|
||||
|
||||
scheduleHeartbeat();
|
||||
tryFlushCache();
|
||||
@@ -129,16 +131,16 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession {
|
||||
Assert.notNull(request, "expected request");
|
||||
Assert.notNull(response, "expected response");
|
||||
Assert.notNull(frameFormat, "expected frameFormat");
|
||||
Assert.isInstanceOf(AsyncServerHttpRequest.class, request, "Expected AsyncServerHttpRequest");
|
||||
this.asyncRequest = (AsyncServerHttpRequest) request;
|
||||
this.request = request;
|
||||
this.response = response;
|
||||
this.asyncControl = new ServletServerHttpAsyncRequestControl(this.request, this.response);
|
||||
this.frameFormat = frameFormat;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public synchronized boolean isActive() {
|
||||
return ((this.asyncRequest != null) && (!this.asyncRequest.isAsyncCompleted()));
|
||||
return ((this.asyncControl != null) && (!this.asyncControl.isCompleted()));
|
||||
}
|
||||
|
||||
protected BlockingQueue<String> getMessageCache() {
|
||||
@@ -146,7 +148,7 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession {
|
||||
}
|
||||
|
||||
protected ServerHttpRequest getRequest() {
|
||||
return this.asyncRequest;
|
||||
return this.request;
|
||||
}
|
||||
|
||||
protected ServerHttpResponse getResponse() {
|
||||
@@ -178,17 +180,18 @@ public abstract class AbstractHttpSockJsSession extends AbstractSockJsSession {
|
||||
|
||||
protected synchronized void resetRequest() {
|
||||
updateLastActiveTime();
|
||||
if (isActive() && this.asyncRequest.isAsyncStarted()) {
|
||||
if (isActive() && this.asyncControl.hasStarted()) {
|
||||
try {
|
||||
logger.debug("Completing async request");
|
||||
this.asyncRequest.completeAsync();
|
||||
this.asyncControl.complete();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.error("Failed to complete async request: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
this.asyncRequest = null;
|
||||
this.request = null;
|
||||
this.response = null;
|
||||
this.asyncControl = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,14 +17,18 @@
|
||||
package org.springframework.web.socket;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.springframework.http.server.AsyncServletServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpAsyncResponseControl;
|
||||
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;
|
||||
import org.springframework.mock.web.test.MockHttpServletResponse;
|
||||
|
||||
/**
|
||||
* Base class for tests using {@link ServerHttpRequest} and {@link ServerHttpResponse}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class AbstractHttpRequestTests {
|
||||
@@ -37,6 +41,8 @@ public class AbstractHttpRequestTests {
|
||||
|
||||
protected MockHttpServletResponse servletResponse;
|
||||
|
||||
protected ServerHttpAsyncResponseControl asyncControl;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -49,10 +55,15 @@ public class AbstractHttpRequestTests {
|
||||
}
|
||||
|
||||
protected void resetRequestAndResponse() {
|
||||
resetRequest();
|
||||
resetResponse();
|
||||
this.asyncControl = new ServletServerHttpAsyncRequestControl(this.request, this.response);
|
||||
}
|
||||
|
||||
protected void resetRequest() {
|
||||
this.servletRequest = new MockHttpServletRequest();
|
||||
this.servletRequest.setAsyncSupported(true);
|
||||
this.request = new AsyncServletServerHttpRequest(this.servletRequest, this.servletResponse);
|
||||
this.request = new ServletServerHttpRequest(this.servletRequest);
|
||||
}
|
||||
|
||||
protected void resetResponse() {
|
||||
|
||||
@@ -146,7 +146,7 @@ public class AbstractSockJsServiceTests extends AbstractHttpRequestTests {
|
||||
|
||||
String body = this.servletResponse.getContentAsString();
|
||||
assertEquals("{\"entropy\"", body.substring(0, body.indexOf(':')));
|
||||
assertEquals(",\"origins\":[\"*:*\"],\"cookie_needed\":true,\"websocket\":true}",
|
||||
assertEquals(",\"origins\":[\"*:*\"],\"cookie_needed\":false,\"websocket\":true}",
|
||||
body.substring(body.indexOf(',')));
|
||||
|
||||
this.service.setDummySessionCookieEnabled(false);
|
||||
|
||||
@@ -20,9 +20,9 @@ import java.io.IOException;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.server.AsyncServletServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.http.server.ServletServerHttpRequest;
|
||||
import org.springframework.http.server.ServletServerHttpResponse;
|
||||
import org.springframework.mock.web.test.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.test.MockHttpServletResponse;
|
||||
@@ -31,7 +31,6 @@ import org.springframework.web.socket.WebSocketHandler;
|
||||
import org.springframework.web.socket.sockjs.support.frame.SockJsFrame;
|
||||
import org.springframework.web.socket.sockjs.support.frame.SockJsFrame.DefaultFrameFormat;
|
||||
import org.springframework.web.socket.sockjs.support.frame.SockJsFrame.FrameFormat;
|
||||
import org.springframework.web.socket.sockjs.transport.session.AbstractHttpSockJsSession;
|
||||
import org.springframework.web.socket.sockjs.transport.session.AbstractHttpSockJsSessionTests.TestAbstractHttpSockJsSession;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
@@ -67,7 +66,7 @@ public class AbstractHttpSockJsSessionTests extends BaseAbstractSockJsSessionTes
|
||||
|
||||
this.servletRequest = new MockHttpServletRequest();
|
||||
this.servletRequest.setAsyncSupported(true);
|
||||
this.request = new AsyncServletServerHttpRequest(this.servletRequest, this.servletResponse);
|
||||
this.request = new ServletServerHttpRequest(this.servletRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user