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,158 @@
|
||||
/*
|
||||
* 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.servlet;
|
||||
|
||||
import static org.easymock.EasyMock.createMock;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
import static org.easymock.EasyMock.verify;
|
||||
import static org.junit.Assert.assertSame;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
/**
|
||||
* A test fixture with HandlerExecutionChain and mock handler interceptors.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class HandlerExecutionChainTests {
|
||||
|
||||
private HandlerExecutionChain chain;
|
||||
|
||||
private Object handler;
|
||||
|
||||
private MockHttpServletRequest request;
|
||||
|
||||
private MockHttpServletResponse response;
|
||||
|
||||
private HandlerInterceptor interceptor1;
|
||||
|
||||
private HandlerInterceptor interceptor2;
|
||||
|
||||
private HandlerInterceptor interceptor3;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.request = new MockHttpServletRequest();
|
||||
this.response= new MockHttpServletResponse() ;
|
||||
|
||||
this.handler = new Object();
|
||||
this.chain = new HandlerExecutionChain(this.handler);
|
||||
|
||||
this.interceptor1 = createMock(HandlerInterceptor.class);
|
||||
this.interceptor2 = createMock(HandlerInterceptor.class);
|
||||
this.interceptor3 = createMock(HandlerInterceptor.class);
|
||||
|
||||
this.chain.addInterceptor(this.interceptor1);
|
||||
this.chain.addInterceptor(this.interceptor2);
|
||||
this.chain.addInterceptor(this.interceptor3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void successScenario() throws Exception {
|
||||
ModelAndView mav = new ModelAndView();
|
||||
|
||||
expect(this.interceptor1.preHandle(this.request, this.response, this.handler)).andReturn(true);
|
||||
expect(this.interceptor2.preHandle(this.request, this.response, this.handler)).andReturn(true);
|
||||
expect(this.interceptor3.preHandle(this.request, this.response, this.handler)).andReturn(true);
|
||||
|
||||
this.interceptor1.postHandle(this.request, this.response, this.handler, mav);
|
||||
this.interceptor2.postHandle(this.request, this.response, this.handler, mav);
|
||||
this.interceptor3.postHandle(this.request, this.response, this.handler, mav);
|
||||
|
||||
this.interceptor3.afterCompletion(this.request, this.response, this.handler, null);
|
||||
this.interceptor2.afterCompletion(this.request, this.response, this.handler, null);
|
||||
this.interceptor1.afterCompletion(this.request, this.response, this.handler, null);
|
||||
|
||||
replay(this.interceptor1, this.interceptor2, this.interceptor3);
|
||||
|
||||
this.chain.applyPreHandle(request, response);
|
||||
this.chain.applyPostHandle(request, response, mav);
|
||||
this.chain.triggerAfterCompletion(this.request, this.response, null);
|
||||
|
||||
verify(this.interceptor1, this.interceptor2, this.interceptor3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void earlyExit() throws Exception {
|
||||
expect(this.interceptor1.preHandle(this.request, this.response, this.handler)).andReturn(true);
|
||||
expect(this.interceptor2.preHandle(this.request, this.response, this.handler)).andReturn(false);
|
||||
|
||||
this.interceptor1.afterCompletion(this.request, this.response, this.handler, null);
|
||||
|
||||
replay(this.interceptor1, this.interceptor2, this.interceptor3);
|
||||
|
||||
this.chain.applyPreHandle(request, response);
|
||||
|
||||
verify(this.interceptor1, this.interceptor2, this.interceptor3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exceptionBeforePreHandle() throws Exception {
|
||||
replay(this.interceptor1, this.interceptor2, this.interceptor3);
|
||||
|
||||
this.chain.triggerAfterCompletion(this.request, this.response, null);
|
||||
|
||||
verify(this.interceptor1, this.interceptor2, this.interceptor3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exceptionDuringPreHandle() throws Exception {
|
||||
Exception ex = new Exception("");
|
||||
|
||||
expect(this.interceptor1.preHandle(this.request, this.response, this.handler)).andReturn(true);
|
||||
expect(this.interceptor2.preHandle(this.request, this.response, this.handler)).andThrow(ex);
|
||||
|
||||
this.interceptor1.afterCompletion(this.request, this.response, this.handler, ex);
|
||||
|
||||
replay(this.interceptor1, this.interceptor2, this.interceptor3);
|
||||
|
||||
try {
|
||||
this.chain.applyPreHandle(request, response);
|
||||
}
|
||||
catch (Exception actual) {
|
||||
assertSame(ex, actual);
|
||||
}
|
||||
this.chain.triggerAfterCompletion(this.request, this.response, ex);
|
||||
|
||||
verify(this.interceptor1, this.interceptor2, this.interceptor3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exceptionAfterPreHandle() throws Exception {
|
||||
Exception ex = new Exception("");
|
||||
|
||||
expect(this.interceptor1.preHandle(this.request, this.response, this.handler)).andReturn(true);
|
||||
expect(this.interceptor2.preHandle(this.request, this.response, this.handler)).andReturn(true);
|
||||
expect(this.interceptor3.preHandle(this.request, this.response, this.handler)).andReturn(true);
|
||||
|
||||
this.interceptor3.afterCompletion(this.request, this.response, this.handler, ex);
|
||||
this.interceptor2.afterCompletion(this.request, this.response, this.handler, ex);
|
||||
this.interceptor1.afterCompletion(this.request, this.response, this.handler, ex);
|
||||
|
||||
replay(this.interceptor1, this.interceptor2, this.interceptor3);
|
||||
|
||||
this.chain.applyPreHandle(request, response);
|
||||
this.chain.triggerAfterCompletion(this.request, this.response, ex);
|
||||
|
||||
verify(this.interceptor1, this.interceptor2, this.interceptor3);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user