Initial cut of Servlet 3.0 based async support
From a programming model perspective, @RequestMapping methods now support two new return value types: * java.util.concurrent.Callable - used by Spring MVC to obtain the return value asynchronously in a separate thread managed transparently by Spring MVC on behalf of the application. * org.springframework.web.context.request.async.DeferredResult - used by the application to produce the return value asynchronously in a separate thread of its own choosing. The high-level idea is that whatever value a controller normally returns, it can now provide it asynchronously, through a Callable or through a DeferredResult, with all remaining processing -- @ResponseBody, view resolution, etc, working just the same but completed outside the main request thread. From an SPI perspective, there are several new types: * AsyncExecutionChain - the central class for managing async request processing through a sequence of Callable instances each representing work required to complete request processing asynchronously. * AsyncWebRequest - provides methods for starting, completing, and configuring async request processing. * StandardServletAsyncWebRequest - Servlet 3 based implementation. * AsyncExecutionChainRunnable - the Runnable used for async request execution. All spring-web and spring-webmvc Filter implementations have been updated to participate in async request execution. The open-session-in-view Filter and interceptors implementations in spring-orm will be updated in a separate pull request. Issue: SPR-8517
This commit is contained in:
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* 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.addDelegatingCallable(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());
|
||||
|
||||
this.chain.setAsyncWebRequest(null);
|
||||
assertFalse(this.chain.isAsyncStarted());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startCallableChainProcessing() throws Exception {
|
||||
this.chain.addDelegatingCallable(new IntegerIncrementingCallable());
|
||||
this.chain.addDelegatingCallable(new IntegerIncrementingCallable());
|
||||
this.chain.setCallable(new Callable<Object>() {
|
||||
public Object call() throws Exception {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
|
||||
this.chain.startCallableChainProcessing();
|
||||
|
||||
assertEquals(3, this.resultSavingCallable.result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startCallableChainProcessing_staleRequest() {
|
||||
this.chain.setCallable(new Callable<Object>() {
|
||||
public Object call() throws Exception {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
|
||||
this.asyncWebRequest.startAsync();
|
||||
this.asyncWebRequest.complete();
|
||||
this.chain.startCallableChainProcessing();
|
||||
Exception ex = this.resultSavingCallable.exception;
|
||||
|
||||
assertNotNull(ex);
|
||||
assertEquals(StaleAsyncWebRequestException.class, ex.getClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startCallableChainProcessing_requiredCallable() {
|
||||
try {
|
||||
this.chain.startCallableChainProcessing();
|
||||
fail("Expected exception");
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
assertThat(ex.getMessage(), containsString("The callable field is required"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startCallableChainProcessing_requiredAsyncWebRequest() {
|
||||
this.chain.setAsyncWebRequest(null);
|
||||
try {
|
||||
this.chain.startCallableChainProcessing();
|
||||
fail("Expected exception");
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
assertThat(ex.getMessage(), containsString("AsyncWebRequest is required"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startDeferredValueProcessing() throws Exception {
|
||||
this.chain.addDelegatingCallable(new IntegerIncrementingCallable());
|
||||
this.chain.addDelegatingCallable(new IntegerIncrementingCallable());
|
||||
|
||||
DeferredResult deferredValue = new DeferredResult();
|
||||
this.chain.startDeferredResultProcessing(deferredValue);
|
||||
|
||||
assertTrue(this.asyncWebRequest.isAsyncStarted());
|
||||
|
||||
deferredValue.set(1);
|
||||
|
||||
assertEquals(3, this.resultSavingCallable.result);
|
||||
}
|
||||
|
||||
@Test(expected=StaleAsyncWebRequestException.class)
|
||||
public void startDeferredValueProcessing_staleRequest() throws Exception {
|
||||
this.asyncWebRequest.startAsync();
|
||||
this.asyncWebRequest.complete();
|
||||
|
||||
DeferredResult deferredValue = new DeferredResult();
|
||||
this.chain.startDeferredResultProcessing(deferredValue);
|
||||
deferredValue.set(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startDeferredValueProcessing_requiredDeferredValue() {
|
||||
try {
|
||||
this.chain.startDeferredResultProcessing(null);
|
||||
fail("Expected exception");
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
assertThat(ex.getMessage(), containsString("A DeferredValue 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 startAsync() {
|
||||
this.asyncStarted = true;
|
||||
}
|
||||
|
||||
public boolean isAsyncStarted() {
|
||||
return this.asyncStarted;
|
||||
}
|
||||
|
||||
public void setTimeout(Long timeout) { }
|
||||
|
||||
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 = getNextCallable().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) getNextCallable().call() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.setNextCallable(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* 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.expect;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
import static org.easymock.EasyMock.reset;
|
||||
import static org.easymock.EasyMock.verify;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
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.MockHttpServletResponse;
|
||||
|
||||
/**
|
||||
* A test fixture with a {@link StandardServletAsyncWebRequest}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class StandardServletAsyncWebRequestTests {
|
||||
|
||||
private StandardServletAsyncWebRequest asyncRequest;
|
||||
|
||||
private HttpServletRequest request;
|
||||
|
||||
private MockHttpServletResponse response;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.request = EasyMock.createMock(HttpServletRequest.class);
|
||||
this.response = new MockHttpServletResponse();
|
||||
this.asyncRequest = new StandardServletAsyncWebRequest(this.request, this.response);
|
||||
this.asyncRequest.setTimeout(60*1000L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAsyncStarted() throws Exception {
|
||||
assertEquals(false, this.asyncRequest.isAsyncStarted());
|
||||
|
||||
startAsync();
|
||||
|
||||
reset(this.request);
|
||||
expect(this.request.isAsyncStarted()).andReturn(true);
|
||||
replay(this.request);
|
||||
|
||||
assertTrue(this.asyncRequest.isAsyncStarted());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isAsyncStarted_stale() throws Exception {
|
||||
this.asyncRequest.onComplete(new AsyncEvent(null));
|
||||
try {
|
||||
this.asyncRequest.isAsyncStarted();
|
||||
fail("expected exception");
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
assertStaleRequestMessage(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startAsync() throws Exception {
|
||||
AsyncContext asyncContext = EasyMock.createMock(AsyncContext.class);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@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);
|
||||
this.asyncRequest.onComplete(new AsyncEvent(null));
|
||||
try {
|
||||
this.asyncRequest.startAsync();
|
||||
fail("expected exception");
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
assertStaleRequestMessage(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void complete_stale() throws Exception {
|
||||
this.asyncRequest.onComplete(new AsyncEvent(null));
|
||||
try {
|
||||
this.asyncRequest.complete();
|
||||
fail("expected exception");
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
assertStaleRequestMessage(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sendError() throws Exception {
|
||||
this.asyncRequest.sendError(HttpStatus.INTERNAL_SERVER_ERROR, "error");
|
||||
assertEquals(500, this.response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sendError_requestAlreadyCompleted() throws Exception {
|
||||
this.asyncRequest.onComplete(new AsyncEvent(null));
|
||||
this.asyncRequest.sendError(HttpStatus.INTERNAL_SERVER_ERROR, "error");
|
||||
assertEquals(200, this.response.getStatus());
|
||||
}
|
||||
|
||||
|
||||
private void assertStaleRequestMessage(IllegalStateException ex) {
|
||||
assertEquals("Cannot use async request after completion", ex.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,16 +16,23 @@
|
||||
|
||||
package org.springframework.web.filter;
|
||||
|
||||
import static org.easymock.EasyMock.createMock;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.notNull;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
import static org.easymock.EasyMock.same;
|
||||
import static org.easymock.EasyMock.verify;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.easymock.MockControl;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Rick Evans
|
||||
@@ -39,28 +46,22 @@ public class CharacterEncodingFilterTests extends TestCase {
|
||||
|
||||
|
||||
public void testForceAlwaysSetsEncoding() throws Exception {
|
||||
MockControl mockRequest = MockControl.createControl(HttpServletRequest.class);
|
||||
HttpServletRequest request = (HttpServletRequest) mockRequest.getMock();
|
||||
HttpServletRequest request = createMock(HttpServletRequest.class);
|
||||
expect(request.getAttribute(AsyncExecutionChain.CALLABLE_CHAIN_ATTRIBUTE)).andReturn(null);
|
||||
request.setAttribute(same(AsyncExecutionChain.CALLABLE_CHAIN_ATTRIBUTE), notNull());
|
||||
request.setCharacterEncoding(ENCODING);
|
||||
mockRequest.setVoidCallable();
|
||||
request.getAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX);
|
||||
mockRequest.setReturnValue(null);
|
||||
expect(request.getAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX)).andReturn(null);
|
||||
request.setAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX, Boolean.TRUE);
|
||||
mockRequest.setVoidCallable();
|
||||
request.removeAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX);
|
||||
mockRequest.setVoidCallable();
|
||||
mockRequest.replay();
|
||||
replay(request);
|
||||
|
||||
MockControl mockResponse = MockControl.createControl(HttpServletResponse.class);
|
||||
HttpServletResponse response = (HttpServletResponse) mockResponse.getMock();
|
||||
HttpServletResponse response = createMock(HttpServletResponse.class);
|
||||
response.setCharacterEncoding(ENCODING);
|
||||
mockResponse.setVoidCallable();
|
||||
mockResponse.replay();
|
||||
replay(response);
|
||||
|
||||
MockControl mockFilter = MockControl.createControl(FilterChain.class);
|
||||
FilterChain filterChain = (FilterChain) mockFilter.getMock();
|
||||
FilterChain filterChain = createMock(FilterChain.class);
|
||||
filterChain.doFilter(request, response);
|
||||
mockFilter.replay();
|
||||
replay(filterChain);
|
||||
|
||||
CharacterEncodingFilter filter = new CharacterEncodingFilter();
|
||||
filter.setForceEncoding(true);
|
||||
@@ -68,32 +69,27 @@ public class CharacterEncodingFilterTests extends TestCase {
|
||||
filter.init(new MockFilterConfig(FILTER_NAME));
|
||||
filter.doFilter(request, response, filterChain);
|
||||
|
||||
mockRequest.verify();
|
||||
mockResponse.verify();
|
||||
mockFilter.verify();
|
||||
verify(request);
|
||||
verify(response);
|
||||
verify(filterChain);
|
||||
}
|
||||
|
||||
public void testEncodingIfEmptyAndNotForced() throws Exception {
|
||||
MockControl mockRequest = MockControl.createControl(HttpServletRequest.class);
|
||||
HttpServletRequest request = (HttpServletRequest) mockRequest.getMock();
|
||||
request.getCharacterEncoding();
|
||||
mockRequest.setReturnValue(null);
|
||||
HttpServletRequest request = createMock(HttpServletRequest.class);
|
||||
expect(request.getAttribute(AsyncExecutionChain.CALLABLE_CHAIN_ATTRIBUTE)).andReturn(null);
|
||||
request.setAttribute(same(AsyncExecutionChain.CALLABLE_CHAIN_ATTRIBUTE), notNull());
|
||||
expect(request.getCharacterEncoding()).andReturn(null);
|
||||
request.setCharacterEncoding(ENCODING);
|
||||
mockRequest.setVoidCallable();
|
||||
request.getAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX);
|
||||
mockRequest.setReturnValue(null);
|
||||
expect(request.getAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX)).andReturn(null);
|
||||
request.setAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX, Boolean.TRUE);
|
||||
mockRequest.setVoidCallable();
|
||||
request.removeAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX);
|
||||
mockRequest.setVoidCallable();
|
||||
mockRequest.replay();
|
||||
replay(request);
|
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
MockControl mockFilter = MockControl.createControl(FilterChain.class);
|
||||
FilterChain filterChain = (FilterChain) mockFilter.getMock();
|
||||
FilterChain filterChain = createMock(FilterChain.class);
|
||||
filterChain.doFilter(request, response);
|
||||
mockFilter.replay();
|
||||
replay(filterChain);
|
||||
|
||||
CharacterEncodingFilter filter = new CharacterEncodingFilter();
|
||||
filter.setForceEncoding(false);
|
||||
@@ -101,60 +97,51 @@ public class CharacterEncodingFilterTests extends TestCase {
|
||||
filter.init(new MockFilterConfig(FILTER_NAME));
|
||||
filter.doFilter(request, response, filterChain);
|
||||
|
||||
mockRequest.verify();
|
||||
mockFilter.verify();
|
||||
verify(request);
|
||||
verify(filterChain);
|
||||
}
|
||||
|
||||
public void testDoesNowtIfEncodingIsNotEmptyAndNotForced() throws Exception {
|
||||
MockControl mockRequest = MockControl.createControl(HttpServletRequest.class);
|
||||
HttpServletRequest request = (HttpServletRequest) mockRequest.getMock();
|
||||
request.getCharacterEncoding();
|
||||
mockRequest.setReturnValue(ENCODING);
|
||||
request.getAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX);
|
||||
mockRequest.setReturnValue(null);
|
||||
HttpServletRequest request = createMock(HttpServletRequest.class);
|
||||
expect(request.getAttribute(AsyncExecutionChain.CALLABLE_CHAIN_ATTRIBUTE)).andReturn(null);
|
||||
request.setAttribute(same(AsyncExecutionChain.CALLABLE_CHAIN_ATTRIBUTE), notNull());
|
||||
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);
|
||||
mockRequest.setVoidCallable();
|
||||
request.removeAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX);
|
||||
mockRequest.setVoidCallable();
|
||||
mockRequest.replay();
|
||||
replay(request);
|
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
MockControl mockFilter = MockControl.createControl(FilterChain.class);
|
||||
FilterChain filterChain = (FilterChain) mockFilter.getMock();
|
||||
FilterChain filterChain = createMock(FilterChain.class);
|
||||
filterChain.doFilter(request, response);
|
||||
mockFilter.replay();
|
||||
replay(filterChain);
|
||||
|
||||
CharacterEncodingFilter filter = new CharacterEncodingFilter();
|
||||
filter.setEncoding(ENCODING);
|
||||
filter.init(new MockFilterConfig(FILTER_NAME));
|
||||
filter.doFilter(request, response, filterChain);
|
||||
|
||||
mockRequest.verify();
|
||||
mockFilter.verify();
|
||||
verify(request);
|
||||
verify(filterChain);
|
||||
}
|
||||
|
||||
public void testWithBeanInitialization() throws Exception {
|
||||
MockControl mockRequest = MockControl.createControl(HttpServletRequest.class);
|
||||
HttpServletRequest request = (HttpServletRequest) mockRequest.getMock();
|
||||
request.getCharacterEncoding();
|
||||
mockRequest.setReturnValue(null);
|
||||
HttpServletRequest request = createMock(HttpServletRequest.class);
|
||||
expect(request.getAttribute(AsyncExecutionChain.CALLABLE_CHAIN_ATTRIBUTE)).andReturn(null);
|
||||
request.setAttribute(same(AsyncExecutionChain.CALLABLE_CHAIN_ATTRIBUTE), notNull());
|
||||
expect(request.getCharacterEncoding()).andReturn(null);
|
||||
request.setCharacterEncoding(ENCODING);
|
||||
mockRequest.setVoidCallable();
|
||||
request.getAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX);
|
||||
mockRequest.setReturnValue(null);
|
||||
expect(request.getAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX)).andReturn(null);
|
||||
request.setAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX, Boolean.TRUE);
|
||||
mockRequest.setVoidCallable();
|
||||
request.removeAttribute(FILTER_NAME + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX);
|
||||
mockRequest.setVoidCallable();
|
||||
mockRequest.replay();
|
||||
replay(request);
|
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
MockControl mockFilter = MockControl.createControl(FilterChain.class);
|
||||
FilterChain filterChain = (FilterChain) mockFilter.getMock();
|
||||
FilterChain filterChain = createMock(FilterChain.class);
|
||||
filterChain.doFilter(request, response);
|
||||
mockFilter.replay();
|
||||
replay(filterChain);
|
||||
|
||||
CharacterEncodingFilter filter = new CharacterEncodingFilter();
|
||||
filter.setEncoding(ENCODING);
|
||||
@@ -162,38 +149,33 @@ public class CharacterEncodingFilterTests extends TestCase {
|
||||
filter.setServletContext(new MockServletContext());
|
||||
filter.doFilter(request, response, filterChain);
|
||||
|
||||
mockRequest.verify();
|
||||
mockFilter.verify();
|
||||
verify(request);
|
||||
verify(filterChain);
|
||||
}
|
||||
|
||||
public void testWithIncompleteInitialization() throws Exception {
|
||||
MockControl mockRequest = MockControl.createControl(HttpServletRequest.class);
|
||||
HttpServletRequest request = (HttpServletRequest) mockRequest.getMock();
|
||||
request.getCharacterEncoding();
|
||||
mockRequest.setReturnValue(null);
|
||||
HttpServletRequest request = createMock(HttpServletRequest.class);
|
||||
expect(request.getAttribute(AsyncExecutionChain.CALLABLE_CHAIN_ATTRIBUTE)).andReturn(null);
|
||||
request.setAttribute(same(AsyncExecutionChain.CALLABLE_CHAIN_ATTRIBUTE), notNull());
|
||||
expect(request.getCharacterEncoding()).andReturn(null);
|
||||
request.setCharacterEncoding(ENCODING);
|
||||
mockRequest.setVoidCallable();
|
||||
request.getAttribute(CharacterEncodingFilter.class.getName() + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX);
|
||||
mockRequest.setReturnValue(null);
|
||||
expect(request.getAttribute(CharacterEncodingFilter.class.getName() + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX)).andReturn(null);
|
||||
request.setAttribute(CharacterEncodingFilter.class.getName() + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX, Boolean.TRUE);
|
||||
mockRequest.setVoidCallable();
|
||||
request.removeAttribute(CharacterEncodingFilter.class.getName() + OncePerRequestFilter.ALREADY_FILTERED_SUFFIX);
|
||||
mockRequest.setVoidCallable();
|
||||
mockRequest.replay();
|
||||
replay(request);
|
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
MockControl mockFilter = MockControl.createControl(FilterChain.class);
|
||||
FilterChain filterChain = (FilterChain) mockFilter.getMock();
|
||||
FilterChain filterChain = createMock(FilterChain.class);
|
||||
filterChain.doFilter(request, response);
|
||||
mockFilter.replay();
|
||||
replay(filterChain);
|
||||
|
||||
CharacterEncodingFilter filter = new CharacterEncodingFilter();
|
||||
filter.setEncoding(ENCODING);
|
||||
filter.doFilter(request, response, filterChain);
|
||||
|
||||
mockRequest.verify();
|
||||
mockFilter.verify();
|
||||
verify(request);
|
||||
verify(filterChain);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user