Refactor Servlet 3 async support
As a result of the refactoring, the AsyncContext dispatch mechanism is used much more centrally. Effectively every asynchronously processed request involves one initial (container) thread, a second thread to produce the handler return value asynchronously, and a third thread as a result of a dispatch back to the container to resume processing of the asynchronous resuilt. Other updates include the addition of a MockAsyncContext and support of related request method in the test packages of spring-web and spring-webmvc. Also an upgrade of a Jetty test dependency required to make tests pass. Issue: SPR-9433
This commit is contained in:
@@ -16,12 +16,16 @@
|
||||
|
||||
package org.springframework.http.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.servlet.GenericServlet;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
@@ -30,20 +34,16 @@ import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.mortbay.jetty.Server;
|
||||
import org.mortbay.jetty.servlet.Context;
|
||||
import org.mortbay.jetty.servlet.ServletHolder;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
public abstract class AbstractHttpRequestFactoryTestCase {
|
||||
|
||||
@@ -58,17 +58,23 @@ public abstract class AbstractHttpRequestFactoryTestCase {
|
||||
int port = FreePortScanner.getFreePort();
|
||||
jettyServer = new Server(port);
|
||||
baseUrl = "http://localhost:" + port;
|
||||
Context jettyContext = new Context(jettyServer, "/");
|
||||
jettyContext.addServlet(new ServletHolder(new EchoServlet()), "/echo");
|
||||
jettyContext.addServlet(new ServletHolder(new StatusServlet(200)), "/status/ok");
|
||||
jettyContext.addServlet(new ServletHolder(new StatusServlet(404)), "/status/notfound");
|
||||
jettyContext.addServlet(new ServletHolder(new MethodServlet("DELETE")), "/methods/delete");
|
||||
jettyContext.addServlet(new ServletHolder(new MethodServlet("GET")), "/methods/get");
|
||||
jettyContext.addServlet(new ServletHolder(new MethodServlet("HEAD")), "/methods/head");
|
||||
jettyContext.addServlet(new ServletHolder(new MethodServlet("OPTIONS")), "/methods/options");
|
||||
jettyContext.addServlet(new ServletHolder(new PostServlet()), "/methods/post");
|
||||
jettyContext.addServlet(new ServletHolder(new MethodServlet("PUT")), "/methods/put");
|
||||
jettyContext.addServlet(new ServletHolder(new MethodServlet("PATCH")), "/methods/patch");
|
||||
|
||||
ServletContextHandler handler = new ServletContextHandler();
|
||||
handler.setContextPath("/");
|
||||
|
||||
handler.addServlet(new ServletHolder(new EchoServlet()), "/echo");
|
||||
handler.addServlet(new ServletHolder(new EchoServlet()), "/echo");
|
||||
handler.addServlet(new ServletHolder(new StatusServlet(200)), "/status/ok");
|
||||
handler.addServlet(new ServletHolder(new StatusServlet(404)), "/status/notfound");
|
||||
handler.addServlet(new ServletHolder(new MethodServlet("DELETE")), "/methods/delete");
|
||||
handler.addServlet(new ServletHolder(new MethodServlet("GET")), "/methods/get");
|
||||
handler.addServlet(new ServletHolder(new MethodServlet("HEAD")), "/methods/head");
|
||||
handler.addServlet(new ServletHolder(new MethodServlet("OPTIONS")), "/methods/options");
|
||||
handler.addServlet(new ServletHolder(new PostServlet()), "/methods/post");
|
||||
handler.addServlet(new ServletHolder(new MethodServlet("PUT")), "/methods/put");
|
||||
handler.addServlet(new ServletHolder(new MethodServlet("PATCH")), "/methods/patch");
|
||||
|
||||
jettyServer.setHandler(handler);
|
||||
jettyServer.start();
|
||||
}
|
||||
|
||||
@@ -179,6 +185,7 @@ public abstract class AbstractHttpRequestFactoryTestCase {
|
||||
/**
|
||||
* Servlet that sets a given status code.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
private static class StatusServlet extends GenericServlet {
|
||||
|
||||
private final int sc;
|
||||
@@ -193,6 +200,7 @@ public abstract class AbstractHttpRequestFactoryTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class MethodServlet extends GenericServlet {
|
||||
|
||||
private final String method;
|
||||
@@ -210,6 +218,7 @@ public abstract class AbstractHttpRequestFactoryTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class PostServlet extends MethodServlet {
|
||||
|
||||
private PostServlet() {
|
||||
@@ -233,6 +242,7 @@ public abstract class AbstractHttpRequestFactoryTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class EchoServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.mock.web;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.AsyncEvent;
|
||||
import javax.servlet.AsyncListener;
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
|
||||
/**
|
||||
* Mock implementation of the {@link AsyncContext} interface.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.2
|
||||
*/
|
||||
public class MockAsyncContext implements AsyncContext {
|
||||
|
||||
private final ServletRequest request;
|
||||
|
||||
private final ServletResponse response;
|
||||
|
||||
private final MockHttpServletRequest mockRequest;
|
||||
|
||||
private final List<AsyncListener> listeners = new ArrayList<AsyncListener>();
|
||||
|
||||
private String dispatchPath;
|
||||
|
||||
private long timeout = 10 * 60 * 1000L;
|
||||
|
||||
public MockAsyncContext(ServletRequest request, ServletResponse response) {
|
||||
this.request = request;
|
||||
this.response = response;
|
||||
this.mockRequest = WebUtils.getNativeRequest(request, MockHttpServletRequest.class);
|
||||
}
|
||||
|
||||
public ServletRequest getRequest() {
|
||||
return this.request;
|
||||
}
|
||||
|
||||
public ServletResponse getResponse() {
|
||||
return this.response;
|
||||
}
|
||||
|
||||
public boolean hasOriginalRequestAndResponse() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getDispatchPath() {
|
||||
return this.dispatchPath;
|
||||
}
|
||||
|
||||
public void dispatch() {
|
||||
dispatch(null);
|
||||
}
|
||||
|
||||
public void dispatch(String path) {
|
||||
dispatch(null, path);
|
||||
}
|
||||
|
||||
public void dispatch(ServletContext context, String path) {
|
||||
this.dispatchPath = path;
|
||||
if (this.mockRequest != null) {
|
||||
this.mockRequest.setDispatcherType(DispatcherType.ASYNC);
|
||||
this.mockRequest.setAsyncStarted(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void complete() {
|
||||
if (this.mockRequest != null) {
|
||||
this.mockRequest.setAsyncStarted(false);
|
||||
}
|
||||
for (AsyncListener listener : this.listeners) {
|
||||
try {
|
||||
listener.onComplete(new AsyncEvent(this, this.request, this.response));
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalStateException("AsyncListener failure", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void start(Runnable run) {
|
||||
}
|
||||
|
||||
public List<AsyncListener> getListeners() {
|
||||
return this.listeners;
|
||||
}
|
||||
|
||||
public void addListener(AsyncListener listener) {
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
|
||||
public void addListener(AsyncListener listener, ServletRequest request, ServletResponse response) {
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
|
||||
public <T extends AsyncListener> T createListener(Class<T> clazz) throws ServletException {
|
||||
return BeanUtils.instantiateClass(clazz);
|
||||
}
|
||||
|
||||
public long getTimeout() {
|
||||
return this.timeout;
|
||||
}
|
||||
|
||||
public void setTimeout(long timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -56,8 +56,8 @@ import org.springframework.util.LinkedCaseInsensitiveMap;
|
||||
|
||||
/**
|
||||
* Mock implementation of the {@link javax.servlet.http.HttpServletRequest}
|
||||
* interface. Supports the Servlet 2.5 API level; throws
|
||||
* {@link UnsupportedOperationException} for all methods introduced in Servlet 3.0.
|
||||
* interface. Supports the Servlet 2.5 API leve. Throws
|
||||
* {@link UnsupportedOperationException} for some methods introduced in Servlet 3.0.
|
||||
*
|
||||
* <p>Used for testing the web framework; also useful for testing
|
||||
* application controllers.
|
||||
@@ -102,7 +102,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
|
||||
public static final String DEFAULT_REMOTE_HOST = "localhost";
|
||||
|
||||
private static final String CONTENT_TYPE_HEADER = "Content-Type";
|
||||
|
||||
|
||||
private static final String CHARSET_PREFIX = "charset=";
|
||||
|
||||
|
||||
@@ -190,6 +190,13 @@ public class MockHttpServletRequest implements HttpServletRequest {
|
||||
|
||||
private boolean requestedSessionIdFromURL = false;
|
||||
|
||||
private boolean asyncSupported = false;
|
||||
|
||||
private boolean asyncStarted = false;
|
||||
|
||||
private MockAsyncContext asyncContext;
|
||||
|
||||
private DispatcherType dispatcherType = DispatcherType.REQUEST;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Constructors
|
||||
@@ -312,7 +319,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
|
||||
this.characterEncoding = characterEncoding;
|
||||
updateContentTypeHeader();
|
||||
}
|
||||
|
||||
|
||||
private void updateContentTypeHeader() {
|
||||
if (this.contentType != null) {
|
||||
StringBuilder sb = new StringBuilder(this.contentType);
|
||||
@@ -679,7 +686,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
|
||||
}
|
||||
doAddHeaderValue(name, value, false);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private void doAddHeaderValue(String name, Object value, boolean replace) {
|
||||
HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name);
|
||||
@@ -898,33 +905,54 @@ public class MockHttpServletRequest implements HttpServletRequest {
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
public AsyncContext getAsyncContext() {
|
||||
throw new UnsupportedOperationException();
|
||||
return this.asyncContext;
|
||||
}
|
||||
|
||||
public void setAsyncContext(MockAsyncContext asyncContext) {
|
||||
this.asyncContext = asyncContext;
|
||||
}
|
||||
|
||||
public DispatcherType getDispatcherType() {
|
||||
throw new UnsupportedOperationException();
|
||||
return this.dispatcherType;
|
||||
}
|
||||
|
||||
public void setDispatcherType(DispatcherType dispatcherType) {
|
||||
this.dispatcherType = dispatcherType;
|
||||
}
|
||||
|
||||
public void setAsyncSupported(boolean asyncSupported) {
|
||||
this.asyncSupported = asyncSupported;
|
||||
}
|
||||
|
||||
public boolean isAsyncSupported() {
|
||||
throw new UnsupportedOperationException();
|
||||
return this.asyncSupported;
|
||||
}
|
||||
|
||||
public AsyncContext startAsync() {
|
||||
throw new UnsupportedOperationException();
|
||||
return startAsync(this, null);
|
||||
}
|
||||
|
||||
public AsyncContext startAsync(ServletRequest arg0, ServletResponse arg1) {
|
||||
throw new UnsupportedOperationException();
|
||||
public AsyncContext startAsync(ServletRequest request, ServletResponse response) {
|
||||
if (!this.asyncSupported) {
|
||||
throw new IllegalStateException("Async not supported");
|
||||
}
|
||||
this.asyncStarted = true;
|
||||
this.asyncContext = new MockAsyncContext(request, response);
|
||||
return this.asyncContext;
|
||||
}
|
||||
|
||||
public void setAsyncStarted(boolean asyncStarted) {
|
||||
this.asyncStarted = asyncStarted;
|
||||
}
|
||||
|
||||
public boolean isAsyncStarted() {
|
||||
throw new UnsupportedOperationException();
|
||||
return this.asyncStarted;
|
||||
}
|
||||
|
||||
public boolean authenticate(HttpServletResponse arg0) throws IOException, ServletException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
public void addPart(Part part) {
|
||||
parts.put(part.getName(), part);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,14 @@
|
||||
|
||||
package org.springframework.web.client;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
@@ -25,6 +33,7 @@ import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.GenericServlet;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
@@ -38,14 +47,13 @@ import org.apache.commons.fileupload.FileItemFactory;
|
||||
import org.apache.commons.fileupload.FileUploadException;
|
||||
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
|
||||
import org.apache.commons.fileupload.servlet.ServletFileUpload;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.mortbay.jetty.Server;
|
||||
import org.mortbay.jetty.servlet.Context;
|
||||
import org.mortbay.jetty.servlet.ServletHolder;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpEntity;
|
||||
@@ -60,8 +68,6 @@ import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/** @author Arjen Poutsma */
|
||||
public class RestTemplateIntegrationTests {
|
||||
|
||||
@@ -80,21 +86,22 @@ public class RestTemplateIntegrationTests {
|
||||
int port = FreePortScanner.getFreePort();
|
||||
jettyServer = new Server(port);
|
||||
baseUrl = "http://localhost:" + port;
|
||||
Context jettyContext = new Context(jettyServer, "/");
|
||||
ServletContextHandler handler = new ServletContextHandler();
|
||||
byte[] bytes = helloWorld.getBytes("UTF-8");
|
||||
contentType = new MediaType("text", "plain", Collections.singletonMap("charset", "utf-8"));
|
||||
jettyContext.addServlet(new ServletHolder(new GetServlet(bytes, contentType)), "/get");
|
||||
jettyContext.addServlet(new ServletHolder(new GetServlet(new byte[0], contentType)), "/get/nothing");
|
||||
jettyContext.addServlet(new ServletHolder(new GetServlet(bytes, null)), "/get/nocontenttype");
|
||||
jettyContext.addServlet(
|
||||
contentType = new MediaType("text", "plain", Collections.singletonMap("charset", "UTF-8"));
|
||||
handler.addServlet(new ServletHolder(new GetServlet(bytes, contentType)), "/get");
|
||||
handler.addServlet(new ServletHolder(new GetServlet(new byte[0], contentType)), "/get/nothing");
|
||||
handler.addServlet(new ServletHolder(new GetServlet(bytes, null)), "/get/nocontenttype");
|
||||
handler.addServlet(
|
||||
new ServletHolder(new PostServlet(helloWorld, baseUrl + "/post/1", bytes, contentType)),
|
||||
"/post");
|
||||
jettyContext.addServlet(new ServletHolder(new StatusCodeServlet(204)), "/status/nocontent");
|
||||
jettyContext.addServlet(new ServletHolder(new StatusCodeServlet(304)), "/status/notmodified");
|
||||
jettyContext.addServlet(new ServletHolder(new ErrorServlet(404)), "/status/notfound");
|
||||
jettyContext.addServlet(new ServletHolder(new ErrorServlet(500)), "/status/server");
|
||||
jettyContext.addServlet(new ServletHolder(new UriServlet()), "/uri/*");
|
||||
jettyContext.addServlet(new ServletHolder(new MultipartServlet()), "/multipart");
|
||||
handler.addServlet(new ServletHolder(new StatusCodeServlet(204)), "/status/nocontent");
|
||||
handler.addServlet(new ServletHolder(new StatusCodeServlet(304)), "/status/notmodified");
|
||||
handler.addServlet(new ServletHolder(new ErrorServlet(404)), "/status/notfound");
|
||||
handler.addServlet(new ServletHolder(new ErrorServlet(500)), "/status/server");
|
||||
handler.addServlet(new ServletHolder(new UriServlet()), "/uri/*");
|
||||
handler.addServlet(new ServletHolder(new MultipartServlet()), "/multipart");
|
||||
jettyServer.setHandler(handler);
|
||||
jettyServer.start();
|
||||
}
|
||||
|
||||
@@ -130,7 +137,7 @@ public class RestTemplateIntegrationTests {
|
||||
String s = template.getForObject(baseUrl + "/get/nothing", String.class);
|
||||
assertNull("Invalid content", s);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void getNoContentTypeHeader() throws UnsupportedEncodingException {
|
||||
byte[] bytes = template.getForObject(baseUrl + "/get/nocontenttype", byte[].class);
|
||||
@@ -141,7 +148,7 @@ public class RestTemplateIntegrationTests {
|
||||
public void getNoContent() {
|
||||
String s = template.getForObject(baseUrl + "/status/nocontent", String.class);
|
||||
assertNull("Invalid content", s);
|
||||
|
||||
|
||||
ResponseEntity<String> entity = template.getForEntity(baseUrl + "/status/nocontent", String.class);
|
||||
assertEquals("Invalid response code", HttpStatus.NO_CONTENT, entity.getStatusCode());
|
||||
assertNull("Invalid content", entity.getBody());
|
||||
|
||||
@@ -1,251 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.context.request.async;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
|
||||
|
||||
/**
|
||||
* Test fixture with an AsyncExecutionChain.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class AsyncExecutionChainTests {
|
||||
|
||||
private AsyncExecutionChain chain;
|
||||
|
||||
private MockHttpServletRequest request;
|
||||
|
||||
private SimpleAsyncWebRequest asyncWebRequest;
|
||||
|
||||
private ResultSavingCallable resultSavingCallable;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.request = new MockHttpServletRequest();
|
||||
this.asyncWebRequest = new SimpleAsyncWebRequest(this.request, new MockHttpServletResponse());
|
||||
this.resultSavingCallable = new ResultSavingCallable();
|
||||
|
||||
this.chain = AsyncExecutionChain.getForCurrentRequest(this.request);
|
||||
this.chain.setTaskExecutor(new SyncTaskExecutor());
|
||||
this.chain.setAsyncWebRequest(this.asyncWebRequest);
|
||||
this.chain.push(this.resultSavingCallable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getForCurrentRequest() throws Exception {
|
||||
assertNotNull(this.chain);
|
||||
assertSame(this.chain, AsyncExecutionChain.getForCurrentRequest(this.request));
|
||||
assertSame(this.chain, this.request.getAttribute(AsyncExecutionChain.CALLABLE_CHAIN_ATTRIBUTE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAsyncStarted() {
|
||||
assertFalse(this.chain.isAsyncStarted());
|
||||
|
||||
this.asyncWebRequest.startAsync();
|
||||
assertTrue(this.chain.isAsyncStarted());
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void setAsyncWebRequestAfterAsyncStarted() {
|
||||
this.asyncWebRequest.startAsync();
|
||||
this.chain.setAsyncWebRequest(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startCallableChainProcessing() throws Exception {
|
||||
this.chain.push(new IntegerIncrementingCallable());
|
||||
this.chain.push(new IntegerIncrementingCallable());
|
||||
this.chain.setLastCallable(new Callable<Object>() {
|
||||
public Object call() throws Exception {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
|
||||
this.chain.startCallableProcessing();
|
||||
|
||||
assertEquals(3, this.resultSavingCallable.result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startCallableChainProcessing_staleRequest() {
|
||||
this.chain.setLastCallable(new Callable<Object>() {
|
||||
public Object call() throws Exception {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
|
||||
this.asyncWebRequest.startAsync();
|
||||
this.asyncWebRequest.complete();
|
||||
this.chain.startCallableProcessing();
|
||||
Exception ex = this.resultSavingCallable.exception;
|
||||
|
||||
assertNotNull(ex);
|
||||
assertEquals(StaleAsyncWebRequestException.class, ex.getClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startCallableChainProcessing_requiredCallable() {
|
||||
try {
|
||||
this.chain.startCallableProcessing();
|
||||
fail("Expected exception");
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
assertEquals(ex.getMessage(), "The last Callable was not set");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startCallableChainProcessing_requiredAsyncWebRequest() {
|
||||
this.chain.setAsyncWebRequest(null);
|
||||
try {
|
||||
this.chain.startCallableProcessing();
|
||||
fail("Expected exception");
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
assertEquals(ex.getMessage(), "AsyncWebRequest was not set");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startDeferredResultProcessing() throws Exception {
|
||||
this.chain.push(new IntegerIncrementingCallable());
|
||||
this.chain.push(new IntegerIncrementingCallable());
|
||||
|
||||
DeferredResult<Integer> deferredResult = new DeferredResult<Integer>();
|
||||
this.chain.startDeferredResultProcessing(deferredResult);
|
||||
|
||||
assertTrue(this.asyncWebRequest.isAsyncStarted());
|
||||
|
||||
deferredResult.set(1);
|
||||
|
||||
assertEquals(3, this.resultSavingCallable.result);
|
||||
}
|
||||
|
||||
@Test(expected=StaleAsyncWebRequestException.class)
|
||||
public void startDeferredResultProcessing_staleRequest() throws Exception {
|
||||
this.asyncWebRequest.startAsync();
|
||||
this.asyncWebRequest.complete();
|
||||
|
||||
DeferredResult<Integer> deferredResult = new DeferredResult<Integer>();
|
||||
this.chain.startDeferredResultProcessing(deferredResult);
|
||||
deferredResult.set(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startDeferredResultProcessing_requiredDeferredResult() {
|
||||
try {
|
||||
this.chain.startDeferredResultProcessing(null);
|
||||
fail("Expected exception");
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
assertThat(ex.getMessage(), containsString("DeferredResult is required"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class SimpleAsyncWebRequest extends ServletWebRequest implements AsyncWebRequest {
|
||||
|
||||
private boolean asyncStarted;
|
||||
|
||||
private boolean asyncCompleted;
|
||||
|
||||
public SimpleAsyncWebRequest(HttpServletRequest request, HttpServletResponse response) {
|
||||
super(request, response);
|
||||
}
|
||||
|
||||
public void setTimeout(Long timeout) { }
|
||||
|
||||
public void setTimeoutHandler(Runnable runnable) { }
|
||||
|
||||
public void startAsync() {
|
||||
this.asyncStarted = true;
|
||||
}
|
||||
|
||||
public boolean isAsyncStarted() {
|
||||
return this.asyncStarted;
|
||||
}
|
||||
|
||||
public void complete() {
|
||||
this.asyncStarted = false;
|
||||
this.asyncCompleted = true;
|
||||
}
|
||||
|
||||
public boolean isAsyncCompleted() {
|
||||
return this.asyncCompleted;
|
||||
}
|
||||
|
||||
public void sendError(HttpStatus status, String message) {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class SyncTaskExecutor extends SimpleAsyncTaskExecutor {
|
||||
|
||||
@Override
|
||||
public void execute(Runnable task, long startTimeout) {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
|
||||
private static class ResultSavingCallable extends AbstractDelegatingCallable {
|
||||
|
||||
Object result;
|
||||
|
||||
Exception exception;
|
||||
|
||||
public Object call() throws Exception {
|
||||
try {
|
||||
this.result = getNext().call();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
this.exception = ex;
|
||||
throw ex;
|
||||
}
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
|
||||
private static class IntegerIncrementingCallable extends AbstractDelegatingCallable {
|
||||
|
||||
public Object call() throws Exception {
|
||||
return ((Integer) getNext().call() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,6 +25,8 @@ import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.web.context.request.async.DeferredResult;
|
||||
import org.springframework.web.context.request.async.StaleAsyncWebRequestException;
|
||||
import org.springframework.web.context.request.async.DeferredResult.DeferredResultHandler;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.context.request.async;
|
||||
|
||||
import static org.easymock.EasyMock.*;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.easymock.EasyMock;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* A test fixture with a {@link StaleAsyncRequestCheckingCallable}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class StaleAsyncRequestCheckingCallableTests {
|
||||
|
||||
private StaleAsyncRequestCheckingCallable callable;
|
||||
|
||||
private AsyncWebRequest asyncWebRequest;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.asyncWebRequest = EasyMock.createMock(AsyncWebRequest.class);
|
||||
this.callable = new StaleAsyncRequestCheckingCallable(asyncWebRequest);
|
||||
this.callable.setNext(new Callable<Object>() {
|
||||
public Object call() throws Exception {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void call_notStale() throws Exception {
|
||||
expect(this.asyncWebRequest.isAsyncCompleted()).andReturn(false);
|
||||
replay(this.asyncWebRequest);
|
||||
|
||||
this.callable.call();
|
||||
|
||||
verify(this.asyncWebRequest);
|
||||
}
|
||||
|
||||
@Test(expected=StaleAsyncWebRequestException.class)
|
||||
public void call_stale() throws Exception {
|
||||
expect(this.asyncWebRequest.isAsyncCompleted()).andReturn(true);
|
||||
replay(this.asyncWebRequest);
|
||||
|
||||
try {
|
||||
this.callable.call();
|
||||
}
|
||||
finally {
|
||||
verify(this.asyncWebRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,25 +17,25 @@
|
||||
package org.springframework.web.context.request.async;
|
||||
|
||||
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
import static org.easymock.EasyMock.reset;
|
||||
import static org.easymock.EasyMock.verify;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.AsyncEvent;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.easymock.EasyMock;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.mock.web.MockAsyncContext;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
/**
|
||||
@@ -47,60 +47,55 @@ public class StandardServletAsyncWebRequestTests {
|
||||
|
||||
private StandardServletAsyncWebRequest asyncRequest;
|
||||
|
||||
private HttpServletRequest request;
|
||||
private MockHttpServletRequest request;
|
||||
|
||||
private MockHttpServletResponse response;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.request = EasyMock.createMock(HttpServletRequest.class);
|
||||
this.request = new MockHttpServletRequest();
|
||||
this.request.setAsyncSupported(true);
|
||||
this.response = new MockHttpServletResponse();
|
||||
this.asyncRequest = new StandardServletAsyncWebRequest(this.request, this.response);
|
||||
this.asyncRequest.setTimeout(60*1000L);
|
||||
this.asyncRequest.setTimeout(44*1000L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAsyncStarted() throws Exception {
|
||||
replay(this.request);
|
||||
assertEquals("Should be \"false\" before startAsync()", false, this.asyncRequest.isAsyncStarted());
|
||||
verify(this.request);
|
||||
assertFalse(this.asyncRequest.isAsyncStarted());
|
||||
|
||||
startAsync();
|
||||
|
||||
reset(this.request);
|
||||
expect(this.request.isAsyncStarted()).andReturn(true);
|
||||
replay(this.request);
|
||||
|
||||
assertTrue("Should be \"true\" true startAsync()", this.asyncRequest.isAsyncStarted());
|
||||
verify(this.request);
|
||||
|
||||
this.asyncRequest.onComplete(new AsyncEvent(null));
|
||||
|
||||
assertFalse("Should be \"false\" after complete()", this.asyncRequest.isAsyncStarted());
|
||||
this.asyncRequest.startAsync();
|
||||
assertTrue(this.asyncRequest.isAsyncStarted());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startAsync() throws Exception {
|
||||
AsyncContext asyncContext = EasyMock.createMock(AsyncContext.class);
|
||||
|
||||
reset(this.request);
|
||||
expect(this.request.isAsyncSupported()).andReturn(true);
|
||||
expect(this.request.startAsync(this.request, this.response)).andStubReturn(asyncContext);
|
||||
replay(this.request);
|
||||
|
||||
asyncContext.addListener(this.asyncRequest);
|
||||
asyncContext.setTimeout(60*1000);
|
||||
replay(asyncContext);
|
||||
|
||||
this.asyncRequest.startAsync();
|
||||
|
||||
verify(this.request);
|
||||
MockAsyncContext asyncContext = (MockAsyncContext) this.request.getAsyncContext();
|
||||
|
||||
assertNotNull(asyncContext);
|
||||
assertEquals("Timeout value not set", 44 * 1000, asyncContext.getTimeout());
|
||||
assertEquals(1, asyncContext.getListeners().size());
|
||||
assertSame(this.asyncRequest, asyncContext.getListeners().get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startAsync_notSupported() throws Exception {
|
||||
expect(this.request.isAsyncSupported()).andReturn(false);
|
||||
replay(this.request);
|
||||
public void startAsyncMultipleTimes() throws Exception {
|
||||
this.asyncRequest.startAsync();
|
||||
this.asyncRequest.startAsync();
|
||||
this.asyncRequest.startAsync();
|
||||
this.asyncRequest.startAsync(); // idempotent
|
||||
|
||||
MockAsyncContext asyncContext = (MockAsyncContext) this.request.getAsyncContext();
|
||||
|
||||
assertNotNull(asyncContext);
|
||||
assertEquals(1, asyncContext.getListeners().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startAsyncNotSupported() throws Exception {
|
||||
this.request.setAsyncSupported(false);
|
||||
try {
|
||||
this.asyncRequest.startAsync();
|
||||
fail("expected exception");
|
||||
@@ -111,60 +106,33 @@ public class StandardServletAsyncWebRequestTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startAsync_alreadyStarted() throws Exception {
|
||||
startAsync();
|
||||
|
||||
reset(this.request);
|
||||
|
||||
expect(this.request.isAsyncSupported()).andReturn(true);
|
||||
expect(this.request.isAsyncStarted()).andReturn(true);
|
||||
replay(this.request);
|
||||
|
||||
try {
|
||||
this.asyncRequest.startAsync();
|
||||
fail("expected exception");
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
assertEquals("Async processing already started", ex.getMessage());
|
||||
}
|
||||
|
||||
verify(this.request);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startAsync_stale() throws Exception {
|
||||
expect(this.request.isAsyncSupported()).andReturn(true);
|
||||
replay(this.request);
|
||||
public void startAsyncAfterCompleted() throws Exception {
|
||||
this.asyncRequest.onComplete(new AsyncEvent(null));
|
||||
try {
|
||||
this.asyncRequest.startAsync();
|
||||
fail("expected exception");
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
assertEquals("Cannot use async request that has completed", ex.getMessage());
|
||||
assertEquals("Async processing has already completed", ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void complete_stale() throws Exception {
|
||||
this.asyncRequest.onComplete(new AsyncEvent(null));
|
||||
this.asyncRequest.complete();
|
||||
|
||||
assertFalse(this.asyncRequest.isAsyncStarted());
|
||||
assertTrue(this.asyncRequest.isAsyncCompleted());
|
||||
public void onTimeoutDefaultBehavior() throws Exception {
|
||||
this.asyncRequest.onTimeout(new AsyncEvent(null));
|
||||
assertEquals(HttpStatus.SERVICE_UNAVAILABLE.value(), this.response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sendError() throws Exception {
|
||||
this.asyncRequest.sendError(HttpStatus.INTERNAL_SERVER_ERROR, "error");
|
||||
assertEquals(500, this.response.getStatus());
|
||||
}
|
||||
public void onTimeoutTimeoutHandler() throws Exception {
|
||||
Runnable timeoutHandler = EasyMock.createMock(Runnable.class);
|
||||
timeoutHandler.run();
|
||||
replay(timeoutHandler);
|
||||
|
||||
@Test
|
||||
public void sendError_stale() throws Exception {
|
||||
this.asyncRequest.onComplete(new AsyncEvent(null));
|
||||
this.asyncRequest.sendError(HttpStatus.INTERNAL_SERVER_ERROR, "error");
|
||||
assertEquals(200, this.response.getStatus());
|
||||
this.asyncRequest.setTimeoutHandler(timeoutHandler);
|
||||
this.asyncRequest.onTimeout(new AsyncEvent(null));
|
||||
|
||||
verify(timeoutHandler);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.context.request.async;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
|
||||
|
||||
/**
|
||||
* Test fixture with an {@link WebAsyncManager}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class WebAsyncManagerTests {
|
||||
|
||||
private WebAsyncManager asyncManager;
|
||||
|
||||
private MockHttpServletRequest request;
|
||||
|
||||
private StubAsyncWebRequest stubAsyncWebRequest;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.request = new MockHttpServletRequest();
|
||||
this.stubAsyncWebRequest = new StubAsyncWebRequest(this.request, new MockHttpServletResponse());
|
||||
|
||||
this.asyncManager = AsyncWebUtils.getAsyncManager(this.request);
|
||||
this.asyncManager.setTaskExecutor(new SyncTaskExecutor());
|
||||
this.asyncManager.setAsyncWebRequest(this.stubAsyncWebRequest);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getForCurrentRequest() throws Exception {
|
||||
assertNotNull(this.asyncManager);
|
||||
assertSame(this.asyncManager, AsyncWebUtils.getAsyncManager(this.request));
|
||||
assertSame(this.asyncManager, this.request.getAttribute(AsyncWebUtils.WEB_ASYNC_MANAGER_ATTRIBUTE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isConcurrentHandlingStarted() {
|
||||
assertFalse(this.asyncManager.isConcurrentHandlingStarted());
|
||||
|
||||
this.stubAsyncWebRequest.startAsync();
|
||||
assertTrue(this.asyncManager.isConcurrentHandlingStarted());
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void setAsyncWebRequestAfterAsyncStarted() {
|
||||
this.stubAsyncWebRequest.startAsync();
|
||||
this.asyncManager.setAsyncWebRequest(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startCallableChainProcessing() throws Exception {
|
||||
this.asyncManager.startCallableProcessing(new Callable<Object>() {
|
||||
public Object call() throws Exception {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
|
||||
assertTrue(this.asyncManager.isConcurrentHandlingStarted());
|
||||
assertTrue(this.stubAsyncWebRequest.isDispatched());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startCallableChainProcessingStaleRequest() {
|
||||
this.stubAsyncWebRequest.setAsyncComplete(true);
|
||||
this.asyncManager.startCallableProcessing(new Callable<Object>() {
|
||||
public Object call() throws Exception {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
|
||||
assertFalse(this.stubAsyncWebRequest.isDispatched());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startCallableChainProcessingCallableRequired() {
|
||||
try {
|
||||
this.asyncManager.startCallableProcessing(null);
|
||||
fail("Expected exception");
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
assertEquals(ex.getMessage(), "Callable is required");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startCallableChainProcessingAsyncWebRequestRequired() {
|
||||
this.request.removeAttribute(AsyncWebUtils.WEB_ASYNC_MANAGER_ATTRIBUTE);
|
||||
this.asyncManager = AsyncWebUtils.getAsyncManager(this.request);
|
||||
try {
|
||||
this.asyncManager.startCallableProcessing(new Callable<Object>() {
|
||||
public Object call() throws Exception {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
fail("Expected exception");
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
assertEquals(ex.getMessage(), "AsyncWebRequest was not set");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startDeferredResultProcessing() throws Exception {
|
||||
DeferredResult<Integer> deferredResult = new DeferredResult<Integer>();
|
||||
this.asyncManager.startDeferredResultProcessing(deferredResult);
|
||||
|
||||
assertTrue(this.asyncManager.isConcurrentHandlingStarted());
|
||||
|
||||
deferredResult.set(25);
|
||||
assertEquals(25, this.asyncManager.getConcurrentResult());
|
||||
}
|
||||
|
||||
@Test(expected=StaleAsyncWebRequestException.class)
|
||||
public void startDeferredResultProcessing_staleRequest() throws Exception {
|
||||
DeferredResult<Integer> deferredResult = new DeferredResult<Integer>();
|
||||
this.asyncManager.startDeferredResultProcessing(deferredResult);
|
||||
|
||||
this.stubAsyncWebRequest.setAsyncComplete(true);
|
||||
deferredResult.set(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startDeferredResultProcessingDeferredResultRequired() {
|
||||
try {
|
||||
this.asyncManager.startDeferredResultProcessing(null);
|
||||
fail("Expected exception");
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
assertThat(ex.getMessage(), containsString("DeferredResult is required"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class StubAsyncWebRequest extends ServletWebRequest implements AsyncWebRequest {
|
||||
|
||||
private boolean asyncStarted;
|
||||
|
||||
private boolean dispatched;
|
||||
|
||||
private boolean asyncComplete;
|
||||
|
||||
public StubAsyncWebRequest(HttpServletRequest request, HttpServletResponse response) {
|
||||
super(request, response);
|
||||
}
|
||||
|
||||
public void setTimeout(Long timeout) { }
|
||||
|
||||
public void setTimeoutHandler(Runnable runnable) { }
|
||||
|
||||
public void startAsync() {
|
||||
this.asyncStarted = true;
|
||||
}
|
||||
|
||||
public boolean isAsyncStarted() {
|
||||
return this.asyncStarted;
|
||||
}
|
||||
|
||||
public void dispatch() {
|
||||
this.dispatched = true;
|
||||
}
|
||||
|
||||
public boolean isDispatched() {
|
||||
return dispatched;
|
||||
}
|
||||
|
||||
public void setAsyncComplete(boolean asyncComplete) {
|
||||
this.asyncComplete = asyncComplete;
|
||||
}
|
||||
|
||||
public boolean isAsyncComplete() {
|
||||
return this.asyncComplete;
|
||||
}
|
||||
|
||||
public void addCompletionHandler(Runnable runnable) {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class SyncTaskExecutor extends SimpleAsyncTaskExecutor {
|
||||
|
||||
@Override
|
||||
public void execute(Runnable task, long startTimeout) {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package org.springframework.web.filter;
|
||||
|
||||
import static org.easymock.EasyMock.createMock;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.expectLastCall;
|
||||
import static org.easymock.EasyMock.notNull;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
import static org.easymock.EasyMock.same;
|
||||
@@ -32,7 +33,7 @@ import junit.framework.TestCase;
|
||||
import org.springframework.mock.web.MockFilterConfig;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.web.context.request.async.AsyncExecutionChain;
|
||||
import org.springframework.web.context.request.async.AsyncWebUtils;
|
||||
|
||||
/**
|
||||
* @author Rick Evans
|
||||
@@ -47,8 +48,7 @@ public class CharacterEncodingFilterTests extends TestCase {
|
||||
|
||||
public void testForceAlwaysSetsEncoding() throws Exception {
|
||||
HttpServletRequest request = createMock(HttpServletRequest.class);
|
||||
expect(request.getAttribute(AsyncExecutionChain.CALLABLE_CHAIN_ATTRIBUTE)).andReturn(null);
|
||||
request.setAttribute(same(AsyncExecutionChain.CALLABLE_CHAIN_ATTRIBUTE), notNull());
|
||||
addAsyncManagerExpectations(request);
|
||||
request.setCharacterEncoding(ENCODING);
|
||||
expect(request.getAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX)).andReturn(null);
|
||||
request.setAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX, Boolean.TRUE);
|
||||
@@ -76,8 +76,7 @@ public class CharacterEncodingFilterTests extends TestCase {
|
||||
|
||||
public void testEncodingIfEmptyAndNotForced() throws Exception {
|
||||
HttpServletRequest request = createMock(HttpServletRequest.class);
|
||||
expect(request.getAttribute(AsyncExecutionChain.CALLABLE_CHAIN_ATTRIBUTE)).andReturn(null);
|
||||
request.setAttribute(same(AsyncExecutionChain.CALLABLE_CHAIN_ATTRIBUTE), notNull());
|
||||
addAsyncManagerExpectations(request);
|
||||
expect(request.getCharacterEncoding()).andReturn(null);
|
||||
request.setCharacterEncoding(ENCODING);
|
||||
expect(request.getAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX)).andReturn(null);
|
||||
@@ -103,8 +102,7 @@ public class CharacterEncodingFilterTests extends TestCase {
|
||||
|
||||
public void testDoesNowtIfEncodingIsNotEmptyAndNotForced() throws Exception {
|
||||
HttpServletRequest request = createMock(HttpServletRequest.class);
|
||||
expect(request.getAttribute(AsyncExecutionChain.CALLABLE_CHAIN_ATTRIBUTE)).andReturn(null);
|
||||
request.setAttribute(same(AsyncExecutionChain.CALLABLE_CHAIN_ATTRIBUTE), notNull());
|
||||
addAsyncManagerExpectations(request);
|
||||
expect(request.getCharacterEncoding()).andReturn(ENCODING);
|
||||
expect(request.getAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX)).andReturn(null);
|
||||
request.setAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX, Boolean.TRUE);
|
||||
@@ -128,8 +126,7 @@ public class CharacterEncodingFilterTests extends TestCase {
|
||||
|
||||
public void testWithBeanInitialization() throws Exception {
|
||||
HttpServletRequest request = createMock(HttpServletRequest.class);
|
||||
expect(request.getAttribute(AsyncExecutionChain.CALLABLE_CHAIN_ATTRIBUTE)).andReturn(null);
|
||||
request.setAttribute(same(AsyncExecutionChain.CALLABLE_CHAIN_ATTRIBUTE), notNull());
|
||||
addAsyncManagerExpectations(request);
|
||||
expect(request.getCharacterEncoding()).andReturn(null);
|
||||
request.setCharacterEncoding(ENCODING);
|
||||
expect(request.getAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX)).andReturn(null);
|
||||
@@ -155,8 +152,7 @@ public class CharacterEncodingFilterTests extends TestCase {
|
||||
|
||||
public void testWithIncompleteInitialization() throws Exception {
|
||||
HttpServletRequest request = createMock(HttpServletRequest.class);
|
||||
expect(request.getAttribute(AsyncExecutionChain.CALLABLE_CHAIN_ATTRIBUTE)).andReturn(null);
|
||||
request.setAttribute(same(AsyncExecutionChain.CALLABLE_CHAIN_ATTRIBUTE), notNull());
|
||||
addAsyncManagerExpectations(request);
|
||||
expect(request.getCharacterEncoding()).andReturn(null);
|
||||
request.setCharacterEncoding(ENCODING);
|
||||
expect(request.getAttribute(CharacterEncodingFilter.class.getName() + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX)).andReturn(null);
|
||||
@@ -178,4 +174,11 @@ public class CharacterEncodingFilterTests extends TestCase {
|
||||
verify(filterChain);
|
||||
}
|
||||
|
||||
|
||||
private void addAsyncManagerExpectations(HttpServletRequest request) {
|
||||
expect(request.getAttribute(AsyncWebUtils.WEB_ASYNC_MANAGER_ATTRIBUTE)).andReturn(null);
|
||||
expectLastCall().anyTimes();
|
||||
request.setAttribute(same(AsyncWebUtils.WEB_ASYNC_MANAGER_ATTRIBUTE), notNull());
|
||||
expectLastCall().anyTimes();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user