Merge pull request #73 from rstoyanchev/mvc-async
HanderInterceptor and OSIV async request changes
This commit is contained in:
commit
158b3c6af8
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* 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.
|
||||
|
|
@ -31,6 +31,8 @@ import org.springframework.orm.hibernate3.SessionFactoryUtils;
|
|||
import org.springframework.orm.hibernate3.SessionHolder;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.request.async.AbstractDelegatingCallable;
|
||||
import org.springframework.web.context.request.async.AsyncExecutionChain;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
|
|
@ -168,6 +170,8 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
|
|||
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
AsyncExecutionChain chain = AsyncExecutionChain.getForCurrentRequest(request);
|
||||
|
||||
SessionFactory sessionFactory = lookupSessionFactory(request);
|
||||
boolean participate = false;
|
||||
|
||||
|
|
@ -180,7 +184,10 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
|
|||
else {
|
||||
logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");
|
||||
Session session = getSession(sessionFactory);
|
||||
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
|
||||
SessionHolder sessionHolder = new SessionHolder(session);
|
||||
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
|
||||
|
||||
chain.addDelegatingCallable(getAsyncCallable(request, sessionFactory, sessionHolder));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
@ -204,6 +211,9 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
|
|||
// single session mode
|
||||
SessionHolder sessionHolder =
|
||||
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
|
||||
if (chain.isAsyncStarted()) {
|
||||
return;
|
||||
}
|
||||
logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");
|
||||
closeSession(sessionHolder.getSession(), sessionFactory);
|
||||
}
|
||||
|
|
@ -279,4 +289,28 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
|
|||
SessionFactoryUtils.closeSession(session);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Callable to extend the use of the open Hibernate Session to the
|
||||
* async thread completing the request.
|
||||
*/
|
||||
private AbstractDelegatingCallable getAsyncCallable(final HttpServletRequest request,
|
||||
final SessionFactory sessionFactory, final SessionHolder sessionHolder) {
|
||||
|
||||
return new AbstractDelegatingCallable() {
|
||||
public Object call() throws Exception {
|
||||
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
|
||||
try {
|
||||
getNextCallable().call();
|
||||
}
|
||||
finally {
|
||||
SessionHolder sessionHolder =
|
||||
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
|
||||
logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
|
||||
SessionFactoryUtils.closeSession(sessionHolder.getSession());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* 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.
|
||||
|
|
@ -18,7 +18,6 @@ package org.springframework.orm.hibernate3.support;
|
|||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Session;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.orm.hibernate3.HibernateAccessor;
|
||||
import org.springframework.orm.hibernate3.SessionFactoryUtils;
|
||||
|
|
@ -26,7 +25,8 @@ import org.springframework.orm.hibernate3.SessionHolder;
|
|||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.context.request.WebRequestInterceptor;
|
||||
import org.springframework.web.context.request.async.AbstractDelegatingCallable;
|
||||
import org.springframework.web.context.request.async.AsyncWebRequestInterceptor;
|
||||
|
||||
/**
|
||||
* Spring web request interceptor that binds a Hibernate <code>Session</code> to the
|
||||
|
|
@ -89,7 +89,7 @@ import org.springframework.web.context.request.WebRequestInterceptor;
|
|||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession
|
||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
||||
*/
|
||||
public class OpenSessionInViewInterceptor extends HibernateAccessor implements WebRequestInterceptor {
|
||||
public class OpenSessionInViewInterceptor extends HibernateAccessor implements AsyncWebRequestInterceptor {
|
||||
|
||||
/**
|
||||
* Suffix that gets appended to the <code>SessionFactory</code>
|
||||
|
|
@ -155,7 +155,8 @@ public class OpenSessionInViewInterceptor extends HibernateAccessor implements W
|
|||
Session session = SessionFactoryUtils.getSession(
|
||||
getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());
|
||||
applyFlushMode(session, false);
|
||||
TransactionSynchronizationManager.bindResource(getSessionFactory(), new SessionHolder(session));
|
||||
SessionHolder sessionHolder = new SessionHolder(session);
|
||||
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
|
||||
}
|
||||
else {
|
||||
// deferred close mode
|
||||
|
|
@ -164,6 +165,39 @@ public class OpenSessionInViewInterceptor extends HibernateAccessor implements W
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a <code>Callable</code> to bind the <code>Hibernate</code> session
|
||||
* to the async request thread.
|
||||
*/
|
||||
public AbstractDelegatingCallable getAsyncCallable(WebRequest request) {
|
||||
String attributeName = getParticipateAttributeName();
|
||||
if ((request.getAttribute(attributeName, WebRequest.SCOPE_REQUEST) != null) || !isSingleSession()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final SessionHolder sessionHolder =
|
||||
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
|
||||
|
||||
return new AbstractDelegatingCallable() {
|
||||
public Object call() throws Exception {
|
||||
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
|
||||
getNextCallable().call();
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbind the Hibernate <code>Session</code> from the main thread but leave
|
||||
* the <code>Session</code> open for further use from the async thread.
|
||||
*/
|
||||
public void postHandleAsyncStarted(WebRequest request) {
|
||||
String attributeName = getParticipateAttributeName();
|
||||
if ((request.getAttribute(attributeName, WebRequest.SCOPE_REQUEST) == null) && isSingleSession()) {
|
||||
TransactionSynchronizationManager.unbindResource(getSessionFactory());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the Hibernate <code>Session</code> before view rendering, if necessary.
|
||||
* <p>Note that this just applies in {@link #isSingleSession() single session mode}!
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* 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.
|
||||
|
|
@ -32,6 +32,8 @@ import org.springframework.orm.hibernate4.SessionFactoryUtils;
|
|||
import org.springframework.orm.hibernate4.SessionHolder;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.request.async.AbstractDelegatingCallable;
|
||||
import org.springframework.web.context.request.async.AsyncExecutionChain;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
|
|
@ -102,6 +104,8 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
|
|||
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
AsyncExecutionChain chain = AsyncExecutionChain.getForCurrentRequest(request);
|
||||
|
||||
SessionFactory sessionFactory = lookupSessionFactory(request);
|
||||
boolean participate = false;
|
||||
|
||||
|
|
@ -112,7 +116,10 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
|
|||
else {
|
||||
logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");
|
||||
Session session = openSession(sessionFactory);
|
||||
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
|
||||
SessionHolder sessionHolder = new SessionHolder(session);
|
||||
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
|
||||
|
||||
chain.addDelegatingCallable(getAsyncCallable(request, sessionFactory, sessionHolder));
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
@ -123,6 +130,9 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
|
|||
if (!participate) {
|
||||
SessionHolder sessionHolder =
|
||||
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
|
||||
if (chain.isAsyncStarted()) {
|
||||
return;
|
||||
}
|
||||
logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
|
||||
SessionFactoryUtils.closeSession(sessionHolder.getSession());
|
||||
}
|
||||
|
|
@ -177,4 +187,28 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Callable to extend the use of the open Hibernate Session to the
|
||||
* async thread completing the request.
|
||||
*/
|
||||
private AbstractDelegatingCallable getAsyncCallable(final HttpServletRequest request,
|
||||
final SessionFactory sessionFactory, final SessionHolder sessionHolder) {
|
||||
|
||||
return new AbstractDelegatingCallable() {
|
||||
public Object call() throws Exception {
|
||||
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
|
||||
try {
|
||||
getNextCallable().call();
|
||||
}
|
||||
finally {
|
||||
SessionHolder sessionHolder =
|
||||
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
|
||||
logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
|
||||
SessionFactoryUtils.closeSession(sessionHolder.getSession());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* 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.
|
||||
|
|
@ -22,7 +22,6 @@ import org.hibernate.FlushMode;
|
|||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.orm.hibernate4.SessionFactoryUtils;
|
||||
|
|
@ -30,7 +29,9 @@ import org.springframework.orm.hibernate4.SessionHolder;
|
|||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.context.request.WebRequestInterceptor;
|
||||
import org.springframework.web.context.request.async.AbstractDelegatingCallable;
|
||||
import org.springframework.web.context.request.async.AsyncExecutionChain;
|
||||
import org.springframework.web.context.request.async.AsyncWebRequestInterceptor;
|
||||
|
||||
/**
|
||||
* Spring web request interceptor that binds a Hibernate <code>Session</code> to the
|
||||
|
|
@ -72,7 +73,7 @@ import org.springframework.web.context.request.WebRequestInterceptor;
|
|||
* @see org.springframework.orm.hibernate4.HibernateTransactionManager
|
||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
||||
*/
|
||||
public class OpenSessionInViewInterceptor implements WebRequestInterceptor {
|
||||
public class OpenSessionInViewInterceptor implements AsyncWebRequestInterceptor {
|
||||
|
||||
/**
|
||||
* Suffix that gets appended to the <code>SessionFactory</code>
|
||||
|
|
@ -112,13 +113,47 @@ public class OpenSessionInViewInterceptor implements WebRequestInterceptor {
|
|||
else {
|
||||
logger.debug("Opening Hibernate Session in OpenSessionInViewInterceptor");
|
||||
Session session = openSession();
|
||||
TransactionSynchronizationManager.bindResource(getSessionFactory(), new SessionHolder(session));
|
||||
SessionHolder sessionHolder = new SessionHolder(session);
|
||||
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
|
||||
}
|
||||
}
|
||||
|
||||
public void postHandle(WebRequest request, ModelMap model) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a <code>Callable</code> to bind the <code>Hibernate</code> session
|
||||
* to the async request thread.
|
||||
*/
|
||||
public AbstractDelegatingCallable getAsyncCallable(WebRequest request) {
|
||||
String attributeName = getParticipateAttributeName();
|
||||
if (request.getAttribute(attributeName, WebRequest.SCOPE_REQUEST) != null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final SessionHolder sessionHolder =
|
||||
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
|
||||
|
||||
return new AbstractDelegatingCallable() {
|
||||
public Object call() throws Exception {
|
||||
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
|
||||
getNextCallable().call();
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbind the Hibernate <code>Session</code> from the main thread leaving
|
||||
* it open for further use from an async thread.
|
||||
*/
|
||||
public void postHandleAsyncStarted(WebRequest request) {
|
||||
String attributeName = getParticipateAttributeName();
|
||||
if (request.getAttribute(attributeName, WebRequest.SCOPE_REQUEST) == null) {
|
||||
TransactionSynchronizationManager.unbindResource(getSessionFactory());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbind the Hibernate <code>Session</code> from the thread and close it).
|
||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* 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.
|
||||
|
|
@ -16,23 +16,35 @@
|
|||
|
||||
package org.springframework.orm.hibernate3.support;
|
||||
|
||||
import static org.easymock.EasyMock.createStrictMock;
|
||||
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.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.easymock.MockControl;
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.classic.Session;
|
||||
import org.hibernate.engine.SessionFactoryImplementor;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.mock.web.MockFilterConfig;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
|
@ -47,307 +59,341 @@ import org.springframework.transaction.support.DefaultTransactionDefinition;
|
|||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
import org.springframework.web.context.request.async.AbstractDelegatingCallable;
|
||||
import org.springframework.web.context.request.async.AsyncExecutionChain;
|
||||
import org.springframework.web.context.request.async.AsyncWebRequest;
|
||||
import org.springframework.web.context.support.StaticWebApplicationContext;
|
||||
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 05.03.2005
|
||||
*/
|
||||
public class OpenSessionInViewTests extends TestCase {
|
||||
public class OpenSessionInViewTests {
|
||||
|
||||
private MockServletContext sc;
|
||||
|
||||
private MockHttpServletRequest request;
|
||||
|
||||
private MockHttpServletResponse response;
|
||||
|
||||
private ServletWebRequest webRequest;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.sc = new MockServletContext();
|
||||
this.request = new MockHttpServletRequest(sc);
|
||||
this.response = new MockHttpServletResponse();
|
||||
this.webRequest = new ServletWebRequest(this.request);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpenSessionInViewInterceptorWithSingleSession() throws Exception {
|
||||
|
||||
//SessionFactory sf = createMock(SessionFactory.class);
|
||||
//Session session = createMock(Session.class);
|
||||
|
||||
MockControl sfControl = MockControl.createControl(SessionFactory.class);
|
||||
final SessionFactory sf = (SessionFactory) sfControl.getMock();
|
||||
MockControl sessionControl = MockControl.createControl(Session.class);
|
||||
Session session = (Session) sessionControl.getMock();
|
||||
|
||||
|
||||
SessionFactory sf = createStrictMock(SessionFactory.class);
|
||||
Session session = createStrictMock(Session.class);
|
||||
|
||||
OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor();
|
||||
interceptor.setSessionFactory(sf);
|
||||
|
||||
MockServletContext sc = new MockServletContext();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(sc);
|
||||
|
||||
//expect(mockStorage.size()).andReturn(expectedValue);
|
||||
|
||||
//expect(sf.openSession()).andReturn(session);
|
||||
sf.openSession();
|
||||
sfControl.setReturnValue(session, 1);
|
||||
session.getSessionFactory();
|
||||
sessionControl.setReturnValue(sf, 2);
|
||||
session.isOpen();
|
||||
sessionControl.setReturnValue(true, 1);
|
||||
expect(sf.openSession()).andReturn(session);
|
||||
expect(session.getSessionFactory()).andReturn(sf);
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
sessionControl.setVoidCallable(1);
|
||||
sfControl.replay();
|
||||
sessionControl.replay();
|
||||
interceptor.preHandle(new ServletWebRequest(request));
|
||||
expect(session.getSessionFactory()).andReturn(sf);
|
||||
expect(session.isOpen()).andReturn(true);
|
||||
replay(sf);
|
||||
replay(session);
|
||||
|
||||
interceptor.preHandle(this.webRequest);
|
||||
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||
|
||||
// check that further invocations simply participate
|
||||
interceptor.preHandle(new ServletWebRequest(request));
|
||||
|
||||
interceptor.preHandle(this.webRequest);
|
||||
assertEquals(session, SessionFactoryUtils.getSession(sf, false));
|
||||
|
||||
interceptor.preHandle(new ServletWebRequest(request));
|
||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
||||
interceptor.preHandle(this.webRequest);
|
||||
interceptor.postHandle(this.webRequest, null);
|
||||
interceptor.afterCompletion(this.webRequest, null);
|
||||
|
||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
||||
interceptor.postHandle(this.webRequest, null);
|
||||
interceptor.afterCompletion(this.webRequest, null);
|
||||
|
||||
interceptor.preHandle(new ServletWebRequest(request));
|
||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
||||
interceptor.preHandle(this.webRequest);
|
||||
interceptor.postHandle(this.webRequest, null);
|
||||
interceptor.afterCompletion(this.webRequest, null);
|
||||
|
||||
sfControl.verify();
|
||||
sessionControl.verify();
|
||||
verify(sf);
|
||||
verify(session);
|
||||
reset(sf);
|
||||
reset(session);
|
||||
replay(sf);
|
||||
replay(session);
|
||||
|
||||
sfControl.reset();
|
||||
sessionControl.reset();
|
||||
sfControl.replay();
|
||||
sessionControl.replay();
|
||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
||||
interceptor.postHandle(this.webRequest, null);
|
||||
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||
sfControl.verify();
|
||||
sessionControl.verify();
|
||||
|
||||
sfControl.reset();
|
||||
sessionControl.reset();
|
||||
session.close();
|
||||
sessionControl.setReturnValue(null, 1);
|
||||
sfControl.replay();
|
||||
sessionControl.replay();
|
||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
||||
verify(sf);
|
||||
verify(session);
|
||||
reset(sf);
|
||||
reset(session);
|
||||
expect(session.close()).andReturn(null);
|
||||
replay(sf);
|
||||
replay(session);
|
||||
|
||||
interceptor.afterCompletion(this.webRequest, null);
|
||||
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
||||
sfControl.verify();
|
||||
sessionControl.verify();
|
||||
|
||||
verify(sf);
|
||||
verify(session);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpenSessionInViewInterceptorAsyncScenario() throws Exception {
|
||||
|
||||
final SessionFactory sf = createStrictMock(SessionFactory.class);
|
||||
Session session = createStrictMock(Session.class);
|
||||
|
||||
OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor();
|
||||
interceptor.setSessionFactory(sf);
|
||||
|
||||
expect(sf.openSession()).andReturn(session);
|
||||
expect(session.getSessionFactory()).andReturn(sf);
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
replay(sf);
|
||||
replay(session);
|
||||
|
||||
interceptor.preHandle(this.webRequest);
|
||||
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||
|
||||
AbstractDelegatingCallable asyncCallable = interceptor.getAsyncCallable(this.webRequest);
|
||||
assertNotNull(asyncCallable);
|
||||
|
||||
interceptor.postHandleAsyncStarted(this.webRequest);
|
||||
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
||||
|
||||
verify(sf);
|
||||
verify(session);
|
||||
|
||||
asyncCallable.setNextCallable(new Callable<Object>() {
|
||||
public Object call() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
asyncCallable.call();
|
||||
assertTrue("Session not bound to async thread", TransactionSynchronizationManager.hasResource(sf));
|
||||
|
||||
verify(sf);
|
||||
verify(session);
|
||||
reset(sf);
|
||||
reset(session);
|
||||
replay(sf);
|
||||
replay(session);
|
||||
|
||||
interceptor.postHandle(this.webRequest, null);
|
||||
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||
|
||||
verify(sf);
|
||||
verify(session);
|
||||
reset(sf);
|
||||
reset(session);
|
||||
expect(session.close()).andReturn(null);
|
||||
replay(sf);
|
||||
replay(session);
|
||||
|
||||
interceptor.afterCompletion(this.webRequest, null);
|
||||
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
||||
|
||||
verify(sf);
|
||||
verify(session);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpenSessionInViewInterceptorWithSingleSessionAndJtaTm() throws Exception {
|
||||
MockControl sfControl = MockControl.createControl(SessionFactoryImplementor.class);
|
||||
final SessionFactoryImplementor sf = (SessionFactoryImplementor) sfControl.getMock();
|
||||
MockControl sessionControl = MockControl.createControl(Session.class);
|
||||
Session session = (Session) sessionControl.getMock();
|
||||
final SessionFactoryImplementor sf = createStrictMock(SessionFactoryImplementor.class);
|
||||
Session session = createStrictMock(Session.class);
|
||||
|
||||
MockControl tmControl = MockControl.createControl(TransactionManager.class);
|
||||
TransactionManager tm = (TransactionManager) tmControl.getMock();
|
||||
tm.getTransaction();
|
||||
tmControl.setReturnValue(null, 2);
|
||||
TransactionManager tm = createStrictMock(TransactionManager.class);
|
||||
expect(tm.getTransaction()).andReturn(null);
|
||||
expect(tm.getTransaction()).andReturn(null);
|
||||
replay(tm);
|
||||
|
||||
OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor();
|
||||
interceptor.setSessionFactory(sf);
|
||||
|
||||
MockServletContext sc = new MockServletContext();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(sc);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
sf.getTransactionManager();
|
||||
sfControl.setReturnValue(tm, 2);
|
||||
sf.openSession();
|
||||
sfControl.setReturnValue(session, 1);
|
||||
session.isOpen();
|
||||
sessionControl.setReturnValue(true, 1);
|
||||
expect(sf.openSession()).andReturn(session);
|
||||
expect(sf.getTransactionManager()).andReturn(tm);
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
sessionControl.setVoidCallable(1);
|
||||
expect(sf.getTransactionManager()).andReturn(tm);
|
||||
expect(session.isOpen()).andReturn(true);
|
||||
|
||||
tmControl.replay();
|
||||
sfControl.replay();
|
||||
sessionControl.replay();
|
||||
replay(sf);
|
||||
replay(session);
|
||||
|
||||
interceptor.preHandle(new ServletWebRequest(request));
|
||||
interceptor.preHandle(this.webRequest);
|
||||
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||
|
||||
// check that further invocations simply participate
|
||||
interceptor.preHandle(new ServletWebRequest(request));
|
||||
interceptor.preHandle(this.webRequest);
|
||||
|
||||
assertEquals(session, SessionFactoryUtils.getSession(sf, false));
|
||||
|
||||
interceptor.preHandle(new ServletWebRequest(request));
|
||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
||||
interceptor.preHandle(this.webRequest);
|
||||
interceptor.postHandle(this.webRequest, null);
|
||||
interceptor.afterCompletion(this.webRequest, null);
|
||||
|
||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
||||
interceptor.postHandle(this.webRequest, null);
|
||||
interceptor.afterCompletion(this.webRequest, null);
|
||||
|
||||
interceptor.preHandle(new ServletWebRequest(request));
|
||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
||||
interceptor.preHandle(this.webRequest);
|
||||
interceptor.postHandle(this.webRequest, null);
|
||||
interceptor.afterCompletion(this.webRequest, null);
|
||||
|
||||
sfControl.verify();
|
||||
sessionControl.verify();
|
||||
verify(sf);
|
||||
verify(session);
|
||||
|
||||
sfControl.reset();
|
||||
sessionControl.reset();
|
||||
sfControl.replay();
|
||||
sessionControl.replay();
|
||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
||||
reset(sf);
|
||||
reset(session);
|
||||
replay(sf);
|
||||
replay(session);
|
||||
|
||||
interceptor.postHandle(this.webRequest, null);
|
||||
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||
sfControl.verify();
|
||||
sessionControl.verify();
|
||||
|
||||
sfControl.reset();
|
||||
sessionControl.reset();
|
||||
session.close();
|
||||
sessionControl.setReturnValue(null, 1);
|
||||
sfControl.replay();
|
||||
sessionControl.replay();
|
||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
||||
verify(sf);
|
||||
verify(session);
|
||||
|
||||
reset(sf);
|
||||
reset(session);
|
||||
expect(session.close()).andReturn(null);
|
||||
replay(sf);
|
||||
replay(session);
|
||||
|
||||
interceptor.afterCompletion(this.webRequest, null);
|
||||
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
||||
sfControl.verify();
|
||||
sessionControl.verify();
|
||||
|
||||
verify(sf);
|
||||
verify(session);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpenSessionInViewInterceptorWithSingleSessionAndFlush() throws Exception {
|
||||
MockControl sfControl = MockControl.createControl(SessionFactory.class);
|
||||
final SessionFactory sf = (SessionFactory) sfControl.getMock();
|
||||
MockControl sessionControl = MockControl.createControl(Session.class);
|
||||
Session session = (Session) sessionControl.getMock();
|
||||
SessionFactory sf = createStrictMock(SessionFactory.class);
|
||||
Session session = createStrictMock(Session.class);
|
||||
|
||||
OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor();
|
||||
interceptor.setSessionFactory(sf);
|
||||
interceptor.setFlushMode(HibernateAccessor.FLUSH_AUTO);
|
||||
|
||||
MockServletContext sc = new MockServletContext();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(sc);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
sf.openSession();
|
||||
sfControl.setReturnValue(session, 1);
|
||||
session.getSessionFactory();
|
||||
sessionControl.setReturnValue(sf);
|
||||
sfControl.replay();
|
||||
sessionControl.replay();
|
||||
interceptor.preHandle(new ServletWebRequest(request));
|
||||
expect(sf.openSession()).andReturn(session);
|
||||
expect(session.getSessionFactory()).andReturn(sf);
|
||||
replay(sf);
|
||||
replay(session);
|
||||
interceptor.preHandle(this.webRequest);
|
||||
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||
sfControl.verify();
|
||||
sessionControl.verify();
|
||||
verify(sf);
|
||||
verify(session);
|
||||
|
||||
sfControl.reset();
|
||||
sessionControl.reset();
|
||||
reset(sf);
|
||||
reset(session);
|
||||
session.flush();
|
||||
sessionControl.setVoidCallable(1);
|
||||
sfControl.replay();
|
||||
sessionControl.replay();
|
||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
||||
replay(sf);
|
||||
replay(session);
|
||||
interceptor.postHandle(this.webRequest, null);
|
||||
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||
sfControl.verify();
|
||||
sessionControl.verify();
|
||||
verify(sf);
|
||||
verify(session);
|
||||
|
||||
sfControl.reset();
|
||||
sessionControl.reset();
|
||||
session.close();
|
||||
sessionControl.setReturnValue(null, 1);
|
||||
sfControl.replay();
|
||||
sessionControl.replay();
|
||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
||||
reset(sf);
|
||||
reset(session);
|
||||
expect(session.close()).andReturn(null);
|
||||
replay(sf);
|
||||
replay(session);
|
||||
interceptor.afterCompletion(this.webRequest, null);
|
||||
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
||||
sfControl.verify();
|
||||
sessionControl.verify();
|
||||
verify(sf);
|
||||
verify(session);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpenSessionInViewInterceptorAndDeferredClose() throws Exception {
|
||||
MockControl sfControl = MockControl.createControl(SessionFactory.class);
|
||||
final SessionFactory sf = (SessionFactory) sfControl.getMock();
|
||||
MockControl sessionControl = MockControl.createControl(Session.class);
|
||||
Session session = (Session) sessionControl.getMock();
|
||||
SessionFactory sf = createStrictMock(SessionFactory.class);
|
||||
Session session = createStrictMock(Session.class);
|
||||
|
||||
OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor();
|
||||
interceptor.setSessionFactory(sf);
|
||||
interceptor.setSingleSession(false);
|
||||
|
||||
MockServletContext sc = new MockServletContext();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(sc);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
sf.openSession();
|
||||
sfControl.setReturnValue(session, 1);
|
||||
session.getSessionFactory();
|
||||
sessionControl.setReturnValue(sf, 1);
|
||||
expect(sf.openSession()).andReturn(session);
|
||||
expect(session.getSessionFactory()).andReturn(sf);
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
sessionControl.setVoidCallable(1);
|
||||
sfControl.replay();
|
||||
sessionControl.replay();
|
||||
replay(sf);
|
||||
replay(session);
|
||||
|
||||
interceptor.preHandle(new ServletWebRequest(request));
|
||||
interceptor.preHandle(this.webRequest);
|
||||
org.hibernate.Session sess = SessionFactoryUtils.getSession(sf, true);
|
||||
SessionFactoryUtils.releaseSession(sess, sf);
|
||||
|
||||
// check that further invocations simply participate
|
||||
interceptor.preHandle(new ServletWebRequest(request));
|
||||
interceptor.preHandle(this.webRequest);
|
||||
|
||||
interceptor.preHandle(new ServletWebRequest(request));
|
||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
||||
interceptor.preHandle(this.webRequest);
|
||||
interceptor.postHandle(this.webRequest, null);
|
||||
interceptor.afterCompletion(this.webRequest, null);
|
||||
|
||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
||||
interceptor.postHandle(this.webRequest, null);
|
||||
interceptor.afterCompletion(this.webRequest, null);
|
||||
|
||||
interceptor.preHandle(new ServletWebRequest(request));
|
||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
||||
interceptor.preHandle(this.webRequest);
|
||||
interceptor.postHandle(this.webRequest, null);
|
||||
interceptor.afterCompletion(this.webRequest, null);
|
||||
|
||||
sfControl.verify();
|
||||
sessionControl.verify();
|
||||
sfControl.reset();
|
||||
sessionControl.reset();
|
||||
verify(sf);
|
||||
verify(session);
|
||||
|
||||
session.close();
|
||||
sessionControl.setReturnValue(null, 1);
|
||||
sfControl.replay();
|
||||
sessionControl.replay();
|
||||
reset(sf);
|
||||
reset(session);
|
||||
expect(session.close()).andReturn(null);
|
||||
replay(sf);
|
||||
replay(session);
|
||||
|
||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
||||
sfControl.verify();
|
||||
sessionControl.verify();
|
||||
interceptor.postHandle(this.webRequest, null);
|
||||
interceptor.afterCompletion(this.webRequest, null);
|
||||
|
||||
verify(sf);
|
||||
verify(session);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpenSessionInViewFilterWithSingleSession() throws Exception {
|
||||
MockControl sfControl = MockControl.createControl(SessionFactory.class);
|
||||
final SessionFactory sf = (SessionFactory) sfControl.getMock();
|
||||
MockControl sessionControl = MockControl.createControl(Session.class);
|
||||
Session session = (Session) sessionControl.getMock();
|
||||
final SessionFactory sf = createStrictMock(SessionFactory.class);
|
||||
Session session = createStrictMock(Session.class);
|
||||
|
||||
sf.openSession();
|
||||
sfControl.setReturnValue(session, 1);
|
||||
session.getSessionFactory();
|
||||
sessionControl.setReturnValue(sf);
|
||||
expect(sf.openSession()).andReturn(session);
|
||||
expect(session.getSessionFactory()).andReturn(sf);
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
sessionControl.setVoidCallable(1);
|
||||
session.close();
|
||||
sessionControl.setReturnValue(null, 1);
|
||||
sfControl.replay();
|
||||
sessionControl.replay();
|
||||
expect(session.close()).andReturn(null);
|
||||
replay(sf);
|
||||
replay(session);
|
||||
|
||||
MockControl sf2Control = MockControl.createControl(SessionFactory.class);
|
||||
final SessionFactory sf2 = (SessionFactory) sf2Control.getMock();
|
||||
MockControl session2Control = MockControl.createControl(Session.class);
|
||||
Session session2 = (Session) session2Control.getMock();
|
||||
final SessionFactory sf2 = createStrictMock(SessionFactory.class);
|
||||
Session session2 = createStrictMock(Session.class);
|
||||
|
||||
sf2.openSession();
|
||||
sf2Control.setReturnValue(session2, 1);
|
||||
session2.getSessionFactory();
|
||||
session2Control.setReturnValue(sf);
|
||||
expect(sf2.openSession()).andReturn(session2);
|
||||
expect(session2.getSessionFactory()).andReturn(sf2);
|
||||
session2.setFlushMode(FlushMode.AUTO);
|
||||
session2Control.setVoidCallable(1);
|
||||
session2.close();
|
||||
session2Control.setReturnValue(null, 1);
|
||||
sf2Control.replay();
|
||||
session2Control.replay();
|
||||
expect(session2.close()).andReturn(null);
|
||||
replay(sf2);
|
||||
replay(session2);
|
||||
|
||||
MockServletContext sc = new MockServletContext();
|
||||
StaticWebApplicationContext wac = new StaticWebApplicationContext();
|
||||
wac.setServletContext(sc);
|
||||
wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf);
|
||||
wac.getDefaultListableBeanFactory().registerSingleton("mySessionFactory", sf2);
|
||||
wac.refresh();
|
||||
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(sc);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter");
|
||||
MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2");
|
||||
|
|
@ -378,44 +424,112 @@ public class OpenSessionInViewTests extends TestCase {
|
|||
|
||||
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
||||
assertFalse(TransactionSynchronizationManager.hasResource(sf2));
|
||||
filter2.doFilter(request, response, filterChain3);
|
||||
filter2.doFilter(this.request, this.response, filterChain3);
|
||||
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
||||
assertFalse(TransactionSynchronizationManager.hasResource(sf2));
|
||||
assertNotNull(request.getAttribute("invoked"));
|
||||
assertNotNull(this.request.getAttribute("invoked"));
|
||||
|
||||
sfControl.verify();
|
||||
sessionControl.verify();
|
||||
sf2Control.verify();
|
||||
session2Control.verify();
|
||||
verify(sf);
|
||||
verify(session);
|
||||
verify(sf2);
|
||||
verify(session2);
|
||||
|
||||
wac.close();
|
||||
}
|
||||
|
||||
public void testOpenSessionInViewFilterWithSingleSessionAndPreBoundSession() throws Exception {
|
||||
MockControl sfControl = MockControl.createControl(SessionFactory.class);
|
||||
final SessionFactory sf = (SessionFactory) sfControl.getMock();
|
||||
MockControl sessionControl = MockControl.createControl(Session.class);
|
||||
Session session = (Session) sessionControl.getMock();
|
||||
@Test
|
||||
public void testOpenSessionInViewFilterWithSingleSessionAsyncScenario() throws Exception {
|
||||
final SessionFactory sf = createStrictMock(SessionFactory.class);
|
||||
Session session = createStrictMock(Session.class);
|
||||
|
||||
sf.openSession();
|
||||
sfControl.setReturnValue(session, 1);
|
||||
session.getSessionFactory();
|
||||
sessionControl.setReturnValue(sf);
|
||||
expect(sf.openSession()).andReturn(session);
|
||||
expect(session.getSessionFactory()).andReturn(sf);
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
sessionControl.setVoidCallable(1);
|
||||
session.close();
|
||||
sessionControl.setReturnValue(null, 1);
|
||||
sfControl.replay();
|
||||
sessionControl.replay();
|
||||
replay(sf);
|
||||
replay(session);
|
||||
|
||||
StaticWebApplicationContext wac = new StaticWebApplicationContext();
|
||||
wac.setServletContext(sc);
|
||||
wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf);
|
||||
wac.refresh();
|
||||
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
|
||||
|
||||
MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter");
|
||||
|
||||
final OpenSessionInViewFilter filter = new OpenSessionInViewFilter();
|
||||
filter.init(filterConfig);
|
||||
|
||||
final FilterChain filterChain = new FilterChain() {
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) {
|
||||
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||
servletRequest.setAttribute("invoked", Boolean.TRUE);
|
||||
}
|
||||
};
|
||||
|
||||
AsyncWebRequest asyncWebRequest = createStrictMock(AsyncWebRequest.class);
|
||||
expect(asyncWebRequest.isAsyncStarted()).andReturn(true);
|
||||
expect(asyncWebRequest.isAsyncStarted()).andReturn(true);
|
||||
replay(asyncWebRequest);
|
||||
|
||||
AsyncExecutionChain chain = AsyncExecutionChain.getForCurrentRequest(this.request);
|
||||
chain.setAsyncWebRequest(asyncWebRequest);
|
||||
|
||||
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
||||
filter.doFilter(this.request, this.response, filterChain);
|
||||
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
||||
assertNotNull(this.request.getAttribute("invoked"));
|
||||
|
||||
verify(sf);
|
||||
verify(session);
|
||||
verify(asyncWebRequest);
|
||||
|
||||
chain.setTaskExecutor(new SyncTaskExecutor());
|
||||
chain.setCallable(new Callable<Object>() {
|
||||
public Object call() {
|
||||
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
reset(asyncWebRequest);
|
||||
asyncWebRequest.startAsync();
|
||||
expect(asyncWebRequest.isAsyncCompleted()).andReturn(false);
|
||||
asyncWebRequest.complete();
|
||||
replay(asyncWebRequest);
|
||||
|
||||
reset(sf);
|
||||
reset(session);
|
||||
expect(session.close()).andReturn(null);
|
||||
replay(sf);
|
||||
replay(session);
|
||||
|
||||
chain.startCallableChainProcessing();
|
||||
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
||||
|
||||
verify(sf);
|
||||
verify(session);
|
||||
verify(asyncWebRequest);
|
||||
|
||||
wac.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpenSessionInViewFilterWithSingleSessionAndPreBoundSession() throws Exception {
|
||||
final SessionFactory sf = createStrictMock(SessionFactory.class);
|
||||
Session session = createStrictMock(Session.class);
|
||||
|
||||
expect(sf.openSession()).andReturn(session);
|
||||
expect(session.getSessionFactory()).andReturn(sf);
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
expect(session.close()).andReturn(null);
|
||||
replay(sf);
|
||||
replay(session);
|
||||
|
||||
MockServletContext sc = new MockServletContext();
|
||||
StaticWebApplicationContext wac = new StaticWebApplicationContext();
|
||||
wac.setServletContext(sc);
|
||||
wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf);
|
||||
wac.refresh();
|
||||
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(sc);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter");
|
||||
MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2");
|
||||
|
|
@ -424,7 +538,7 @@ public class OpenSessionInViewTests extends TestCase {
|
|||
OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor();
|
||||
interceptor.setSessionFactory(sf);
|
||||
|
||||
interceptor.preHandle(new ServletWebRequest(request));
|
||||
interceptor.preHandle(this.webRequest);
|
||||
|
||||
final OpenSessionInViewFilter filter = new OpenSessionInViewFilter();
|
||||
filter.init(filterConfig);
|
||||
|
|
@ -437,74 +551,57 @@ public class OpenSessionInViewTests extends TestCase {
|
|||
};
|
||||
|
||||
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||
filter.doFilter(request, response, filterChain);
|
||||
filter.doFilter(this.request, this.response, filterChain);
|
||||
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||
assertNotNull(request.getAttribute("invoked"));
|
||||
assertNotNull(this.request.getAttribute("invoked"));
|
||||
|
||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
||||
interceptor.postHandle(this.webRequest, null);
|
||||
interceptor.afterCompletion(this.webRequest, null);
|
||||
|
||||
sfControl.verify();
|
||||
sessionControl.verify();
|
||||
verify(sf);
|
||||
verify(session);
|
||||
|
||||
wac.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpenSessionInViewFilterWithDeferredClose() throws Exception {
|
||||
MockControl sfControl = MockControl.createControl(SessionFactory.class);
|
||||
final SessionFactory sf = (SessionFactory) sfControl.getMock();
|
||||
final MockControl sessionControl = MockControl.createControl(Session.class);
|
||||
final Session session = (Session) sessionControl.getMock();
|
||||
final SessionFactory sf = createStrictMock(SessionFactory.class);
|
||||
final Session session = createStrictMock(Session.class);
|
||||
|
||||
sf.openSession();
|
||||
sfControl.setReturnValue(session, 1);
|
||||
session.getSessionFactory();
|
||||
sessionControl.setReturnValue(sf);
|
||||
session.getFlushMode();
|
||||
sessionControl.setReturnValue(FlushMode.MANUAL, 1);
|
||||
expect(sf.openSession()).andReturn(session);
|
||||
expect(session.getSessionFactory()).andReturn(sf);
|
||||
expect(session.getFlushMode()).andReturn(FlushMode.MANUAL);
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
sessionControl.setVoidCallable(1);
|
||||
sfControl.replay();
|
||||
sessionControl.replay();
|
||||
replay(sf);
|
||||
replay(session);
|
||||
|
||||
MockControl sf2Control = MockControl.createControl(SessionFactory.class);
|
||||
final SessionFactory sf2 = (SessionFactory) sf2Control.getMock();
|
||||
final MockControl session2Control = MockControl.createControl(Session.class);
|
||||
final Session session2 = (Session) session2Control.getMock();
|
||||
MockControl txControl = MockControl.createControl(Transaction.class);
|
||||
Transaction tx = (Transaction) txControl.getMock();
|
||||
MockControl conControl = MockControl.createControl(Connection.class);
|
||||
Connection con = (Connection) conControl.getMock();
|
||||
final SessionFactory sf2 = createStrictMock(SessionFactory.class);
|
||||
final Session session2 = createStrictMock(Session.class);
|
||||
|
||||
sf2.openSession();
|
||||
sf2Control.setReturnValue(session2, 1);
|
||||
session2.beginTransaction();
|
||||
session2Control.setReturnValue(tx, 1);
|
||||
session2.connection();
|
||||
session2Control.setReturnValue(con, 2);
|
||||
Transaction tx = createStrictMock(Transaction.class);
|
||||
Connection con = createStrictMock(Connection.class);
|
||||
|
||||
expect(sf2.openSession()).andReturn(session2);
|
||||
expect(session2.connection()).andReturn(con);
|
||||
expect(session2.beginTransaction()).andReturn(tx);
|
||||
expect(session2.isConnected()).andReturn(true);
|
||||
expect(session2.connection()).andReturn(con);
|
||||
tx.commit();
|
||||
txControl.setVoidCallable(1);
|
||||
session2.isConnected();
|
||||
session2Control.setReturnValue(true, 1);
|
||||
con.isReadOnly();
|
||||
conControl.setReturnValue(false, 1);
|
||||
expect(con.isReadOnly()).andReturn(false);
|
||||
session2.setFlushMode(FlushMode.MANUAL);
|
||||
session2Control.setVoidCallable(1);
|
||||
|
||||
sf2Control.replay();
|
||||
session2Control.replay();
|
||||
txControl.replay();
|
||||
conControl.replay();
|
||||
replay(sf2);
|
||||
replay(session2);
|
||||
replay(tx);
|
||||
replay(con);
|
||||
|
||||
MockServletContext sc = new MockServletContext();
|
||||
StaticWebApplicationContext wac = new StaticWebApplicationContext();
|
||||
wac.setServletContext(sc);
|
||||
wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf);
|
||||
wac.getDefaultListableBeanFactory().registerSingleton("mySessionFactory", sf2);
|
||||
wac.refresh();
|
||||
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(sc);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter");
|
||||
MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2");
|
||||
|
|
@ -526,12 +623,11 @@ public class OpenSessionInViewTests extends TestCase {
|
|||
SessionFactoryUtils.releaseSession(sess, sf);
|
||||
tm.commit(ts);
|
||||
|
||||
sessionControl.verify();
|
||||
sessionControl.reset();
|
||||
verify(session);
|
||||
reset(session);
|
||||
|
||||
session.close();
|
||||
sessionControl.setReturnValue(null, 1);
|
||||
sessionControl.replay();
|
||||
expect(session.close()).andReturn(null);
|
||||
replay(session);
|
||||
|
||||
servletRequest.setAttribute("invoked", Boolean.TRUE);
|
||||
}
|
||||
|
|
@ -545,12 +641,11 @@ public class OpenSessionInViewTests extends TestCase {
|
|||
TransactionStatus ts = tm.getTransaction(new DefaultTransactionDefinition());
|
||||
tm.commit(ts);
|
||||
|
||||
session2Control.verify();
|
||||
session2Control.reset();
|
||||
verify(session2);
|
||||
reset(session2);
|
||||
|
||||
session2.close();
|
||||
session2Control.setReturnValue(null, 1);
|
||||
session2Control.replay();
|
||||
expect(session2.close()).andReturn(null);
|
||||
replay(session2);
|
||||
|
||||
filter.doFilter(servletRequest, servletResponse, filterChain);
|
||||
}
|
||||
|
|
@ -558,44 +653,48 @@ public class OpenSessionInViewTests extends TestCase {
|
|||
|
||||
FilterChain filterChain3 = new PassThroughFilterChain(filter2, filterChain2);
|
||||
|
||||
filter2.doFilter(request, response, filterChain3);
|
||||
assertNotNull(request.getAttribute("invoked"));
|
||||
filter2.doFilter(this.request, this.response, filterChain3);
|
||||
assertNotNull(this.request.getAttribute("invoked"));
|
||||
|
||||
sfControl.verify();
|
||||
sessionControl.verify();
|
||||
sf2Control.verify();
|
||||
session2Control.verify();
|
||||
txControl.verify();
|
||||
conControl.verify();
|
||||
verify(sf);
|
||||
verify(session);
|
||||
|
||||
verify(sf2);
|
||||
verify(session2);
|
||||
verify(tx);
|
||||
verify(con);
|
||||
|
||||
wac.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpenSessionInViewFilterWithDeferredCloseAndAlreadyActiveDeferredClose() throws Exception {
|
||||
MockControl sfControl = MockControl.createControl(SessionFactory.class);
|
||||
final SessionFactory sf = (SessionFactory) sfControl.getMock();
|
||||
final MockControl sessionControl = MockControl.createControl(Session.class);
|
||||
final Session session = (Session) sessionControl.getMock();
|
||||
final SessionFactory sf = createStrictMock(SessionFactory.class);
|
||||
final Session session = createStrictMock(Session.class);
|
||||
|
||||
sf.openSession();
|
||||
sfControl.setReturnValue(session, 1);
|
||||
session.getSessionFactory();
|
||||
sessionControl.setReturnValue(sf);
|
||||
session.getFlushMode();
|
||||
sessionControl.setReturnValue(FlushMode.MANUAL, 1);
|
||||
expect(sf.openSession()).andReturn(session);
|
||||
expect(session.getSessionFactory()).andReturn(sf);
|
||||
expect(session.getFlushMode()).andReturn(FlushMode.MANUAL);
|
||||
session.setFlushMode(FlushMode.MANUAL);
|
||||
sessionControl.setVoidCallable(1);
|
||||
sfControl.replay();
|
||||
sessionControl.replay();
|
||||
replay(sf);
|
||||
replay(session);
|
||||
|
||||
// sf.openSession();
|
||||
// sfControl.setReturnValue(session, 1);
|
||||
// session.getSessionFactory();
|
||||
// sessionControl.setReturnValue(sf);
|
||||
// session.getFlushMode();
|
||||
// sessionControl.setReturnValue(FlushMode.MANUAL, 1);
|
||||
// session.setFlushMode(FlushMode.MANUAL);
|
||||
// sessionControl.setVoidCallable(1);
|
||||
// sfControl.replay();
|
||||
// sessionControl.replay();
|
||||
|
||||
MockServletContext sc = new MockServletContext();
|
||||
StaticWebApplicationContext wac = new StaticWebApplicationContext();
|
||||
wac.setServletContext(sc);
|
||||
wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf);
|
||||
wac.refresh();
|
||||
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(sc);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter");
|
||||
MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2");
|
||||
|
|
@ -607,7 +706,7 @@ public class OpenSessionInViewTests extends TestCase {
|
|||
interceptor.setSessionFactory(sf);
|
||||
interceptor.setSingleSession(false);
|
||||
|
||||
interceptor.preHandle(new ServletWebRequest(request));
|
||||
interceptor.preHandle(webRequest);
|
||||
|
||||
final OpenSessionInViewFilter filter = new OpenSessionInViewFilter();
|
||||
filter.init(filterConfig);
|
||||
|
|
@ -623,15 +722,14 @@ public class OpenSessionInViewTests extends TestCase {
|
|||
SessionFactoryUtils.releaseSession(sess, sf);
|
||||
tm.commit(ts);
|
||||
|
||||
sessionControl.verify();
|
||||
sessionControl.reset();
|
||||
verify(session);
|
||||
reset(session);
|
||||
try {
|
||||
session.close();
|
||||
expect(session.close()).andReturn(null);
|
||||
}
|
||||
catch (HibernateException ex) {
|
||||
}
|
||||
sessionControl.setReturnValue(null, 1);
|
||||
sessionControl.replay();
|
||||
replay(session);
|
||||
|
||||
servletRequest.setAttribute("invoked", Boolean.TRUE);
|
||||
}
|
||||
|
|
@ -644,16 +742,25 @@ public class OpenSessionInViewTests extends TestCase {
|
|||
}
|
||||
};
|
||||
|
||||
filter.doFilter(request, response, filterChain2);
|
||||
assertNotNull(request.getAttribute("invoked"));
|
||||
filter.doFilter(this.request, this.response, filterChain2);
|
||||
assertNotNull(this.request.getAttribute("invoked"));
|
||||
|
||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
||||
interceptor.postHandle(webRequest, null);
|
||||
interceptor.afterCompletion(webRequest, null);
|
||||
|
||||
sfControl.verify();
|
||||
sessionControl.verify();
|
||||
verify(sf);
|
||||
verify(session);
|
||||
|
||||
wac.close();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class SyncTaskExecutor extends SimpleAsyncTaskExecutor {
|
||||
|
||||
@Override
|
||||
public void execute(Runnable task, long startTimeout) {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ import javax.servlet.ServletRequest;
|
|||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.context.request.async.DeferredResult.DeferredResultHandler;
|
||||
|
||||
/**
|
||||
|
|
@ -77,6 +79,20 @@ public final class AsyncExecutionChain {
|
|||
return chain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the AsyncExecutionChain for the current request.
|
||||
* Or if not found, create an instance and associate it with the request.
|
||||
*/
|
||||
public static AsyncExecutionChain getForCurrentRequest(WebRequest request) {
|
||||
int scope = RequestAttributes.SCOPE_REQUEST;
|
||||
AsyncExecutionChain chain = (AsyncExecutionChain) request.getAttribute(CALLABLE_CHAIN_ATTRIBUTE, scope);
|
||||
if (chain == null) {
|
||||
chain = new AsyncExecutionChain();
|
||||
request.setAttribute(CALLABLE_CHAIN_ATTRIBUTE, chain, scope);
|
||||
}
|
||||
return chain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide an instance of an AsyncWebRequest.
|
||||
* This property must be set before async request processing can begin.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* 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 java.util.concurrent.Callable;
|
||||
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.context.request.WebRequestInterceptor;
|
||||
|
||||
/**
|
||||
* Extends {@link WebRequestInterceptor} with lifecycle methods specific to async
|
||||
* request processing.
|
||||
*
|
||||
* <p>This is the sequence of events on the main thread in an async scenario:
|
||||
* <ol>
|
||||
* <li>{@link #preHandle(WebRequest)}
|
||||
* <li>{@link #getAsyncCallable(WebRequest)}
|
||||
* <li>... <em>handler execution</em>
|
||||
* <li>{@link #postHandleAsyncStarted(WebRequest)}
|
||||
* </ol>
|
||||
*
|
||||
* <p>This is the sequence of events on the async thread:
|
||||
* <ol>
|
||||
* <li>Async {@link Callable#call()} (the {@code Callable} returned by {@code getAsyncCallable})
|
||||
* <li>... <em>async handler execution</em>
|
||||
* <li>{@link #postHandle(WebRequest, org.springframework.ui.ModelMap)}
|
||||
* <li>{@link #afterCompletion(WebRequest, Exception)}
|
||||
* </ol>
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.2
|
||||
*/
|
||||
public interface AsyncWebRequestInterceptor extends WebRequestInterceptor {
|
||||
|
||||
/**
|
||||
* Invoked <em>after</em> {@link #preHandle(WebRequest)} and <em>before</em>
|
||||
* the handler is executed. The returned {@link Callable} is used only if
|
||||
* handler execution leads to teh start of async processing. It is invoked
|
||||
* the async thread before the request is handled fro.
|
||||
* <p>Implementations can use this <code>Callable</code> to initialize
|
||||
* ThreadLocal attributes on the async thread.
|
||||
* @return a {@link Callable} instance or <code>null</code>
|
||||
*/
|
||||
AbstractDelegatingCallable getAsyncCallable(WebRequest request);
|
||||
|
||||
/**
|
||||
* Invoked <em>after</em> the execution of a handler if the handler started
|
||||
* async processing instead of handling the request. Effectively this method
|
||||
* is invoked on the way out of the main processing thread instead of
|
||||
* {@link #postHandle(WebRequest, org.springframework.ui.ModelMap)}. The
|
||||
* <code>postHandle</code> method is invoked after the request is handled
|
||||
* in the async thread.
|
||||
* <p>Implementations of this method can ensure ThreadLocal attributes bound
|
||||
* to the main thread are cleared and also prepare for binding them to the
|
||||
* async thread.
|
||||
*/
|
||||
void postHandleAsyncStarted(WebRequest request);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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 java.util.concurrent.Callable;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.context.request.async.AbstractDelegatingCallable;
|
||||
|
||||
/**
|
||||
* Extends {@link HanderInterceptor} with lifecycle methods specific to async
|
||||
* request processing.
|
||||
*
|
||||
* <p>This is the sequence of events on the main thread in an async scenario:
|
||||
* <ol>
|
||||
* <li>{@link #preHandle(WebRequest)}
|
||||
* <li>{@link #getAsyncCallable(WebRequest)}
|
||||
* <li>... <em>handler execution</em>
|
||||
* <li>{@link #postHandleAsyncStarted(WebRequest)}
|
||||
* </ol>
|
||||
*
|
||||
* <p>This is the sequence of events on the async thread:
|
||||
* <ol>
|
||||
* <li>Async {@link Callable#call()} (the {@code Callable} returned by {@code getAsyncCallable})
|
||||
* <li>... <em>async handler execution</em>
|
||||
* <li>{@link #postHandle(WebRequest, org.springframework.ui.ModelMap)}
|
||||
* <li>{@link #afterCompletion(WebRequest, Exception)}
|
||||
* </ol>
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.2
|
||||
*/
|
||||
public interface AsyncHandlerInterceptor extends HandlerInterceptor {
|
||||
|
||||
/**
|
||||
* Invoked <em>after</em> {@link #preHandle(WebRequest)} and <em>before</em>
|
||||
* the handler is executed. The returned {@link Callable} is used only if
|
||||
* handler execution leads to teh start of async processing. It is invoked
|
||||
* the async thread before the request is handled fro.
|
||||
* <p>Implementations can use this <code>Callable</code> to initialize
|
||||
* ThreadLocal attributes on the async thread.
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @param handler chosen handler to execute, for type and/or instance examination
|
||||
* @return a {@link Callable} instance or <code>null</code>
|
||||
*/
|
||||
AbstractDelegatingCallable getAsyncCallable(HttpServletRequest request, HttpServletResponse response, Object handler);
|
||||
|
||||
/**
|
||||
* Invoked <em>after</em> the execution of a handler if the handler started
|
||||
* async processing instead of handling the request. Effectively this method
|
||||
* is invoked on the way out of the main processing thread instead of
|
||||
* {@link #postHandle(WebRequest, org.springframework.ui.ModelMap)}. The
|
||||
* <code>postHandle</code> method is invoked after the request is handled
|
||||
* in the async thread.
|
||||
* <p>Implementations of this method can ensure ThreadLocal attributes bound
|
||||
* to the main thread are cleared and also prepare for binding them to the
|
||||
* async thread.
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @param handler chosen handler to execute, for type and/or instance examination
|
||||
*/
|
||||
void postHandleAsyncStarted(HttpServletRequest request, HttpServletResponse response, Object handler);
|
||||
|
||||
}
|
||||
|
|
@ -941,6 +941,8 @@ public class DispatcherServlet extends FrameworkServlet {
|
|||
return;
|
||||
}
|
||||
|
||||
mappedHandler.addDelegatingCallables(processedRequest, response);
|
||||
|
||||
asyncChain.addDelegatingCallable(
|
||||
getDispatchAsyncCallable(mappedHandler, request, response, processedRequest));
|
||||
|
||||
|
|
@ -948,6 +950,7 @@ public class DispatcherServlet extends FrameworkServlet {
|
|||
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
|
||||
|
||||
if (asyncChain.isAsyncStarted()) {
|
||||
mappedHandler.applyPostHandleAsyncStarted(processedRequest, response);
|
||||
logger.debug("Exiting request thread and leaving the response open");
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.context.request.async.AsyncExecutionChain;
|
||||
|
||||
/**
|
||||
* Handler execution chain, consisting of handler object and any handler interceptors.
|
||||
|
|
@ -139,7 +140,7 @@ public class HandlerExecutionChain {
|
|||
}
|
||||
|
||||
/**
|
||||
* Apply preHandle methods of registered interceptors.
|
||||
* Apply postHandle methods of registered interceptors.
|
||||
*/
|
||||
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv)
|
||||
throws Exception {
|
||||
|
|
@ -153,6 +154,53 @@ public class HandlerExecutionChain {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add delegating, async Callable instances to the {@link AsyncExecutionChain}
|
||||
* for use in case of asynchronous request processing.
|
||||
*/
|
||||
void addDelegatingCallables(HttpServletRequest request, HttpServletResponse response)
|
||||
throws Exception {
|
||||
|
||||
if (getInterceptors() == null) {
|
||||
return;
|
||||
}
|
||||
for (int i = getInterceptors().length - 1; i >= 0; i--) {
|
||||
HandlerInterceptor interceptor = getInterceptors()[i];
|
||||
if (interceptor instanceof AsyncHandlerInterceptor) {
|
||||
try {
|
||||
AsyncHandlerInterceptor asyncInterceptor = (AsyncHandlerInterceptor) interceptor;
|
||||
AsyncExecutionChain chain = AsyncExecutionChain.getForCurrentRequest(request);
|
||||
chain.addDelegatingCallable(asyncInterceptor.getAsyncCallable(request, response, this.handler));
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.error("HandlerInterceptor.addAsyncCallables threw exception", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger postHandleAsyncStarted callbacks on the mapped HandlerInterceptors.
|
||||
*/
|
||||
void applyPostHandleAsyncStarted(HttpServletRequest request, HttpServletResponse response)
|
||||
throws Exception {
|
||||
|
||||
if (getInterceptors() == null) {
|
||||
return;
|
||||
}
|
||||
for (int i = getInterceptors().length - 1; i >= 0; i--) {
|
||||
HandlerInterceptor interceptor = getInterceptors()[i];
|
||||
if (interceptor instanceof AsyncHandlerInterceptor) {
|
||||
try {
|
||||
((AsyncHandlerInterceptor) interceptor).postHandleAsyncStarted(request, response, this.handler);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.error("HandlerInterceptor.postHandleAsyncStarted threw exception", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
|
||||
* Will just invoke afterCompletion for all interceptors whose preHandle invocation
|
||||
|
|
|
|||
|
|
@ -21,7 +21,9 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.request.WebRequestInterceptor;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.context.request.async.AbstractDelegatingCallable;
|
||||
import org.springframework.web.context.request.async.AsyncWebRequestInterceptor;
|
||||
import org.springframework.web.servlet.AsyncHandlerInterceptor;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
|
|
@ -33,7 +35,7 @@ import org.springframework.web.servlet.ModelAndView;
|
|||
* @see org.springframework.web.context.request.WebRequestInterceptor
|
||||
* @see org.springframework.web.servlet.HandlerInterceptor
|
||||
*/
|
||||
public class WebRequestHandlerInterceptorAdapter implements HandlerInterceptor {
|
||||
public class WebRequestHandlerInterceptorAdapter implements AsyncHandlerInterceptor {
|
||||
|
||||
private final WebRequestInterceptor requestInterceptor;
|
||||
|
||||
|
|
@ -55,6 +57,25 @@ public class WebRequestHandlerInterceptorAdapter implements HandlerInterceptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
public AbstractDelegatingCallable getAsyncCallable(HttpServletRequest request,
|
||||
HttpServletResponse response, Object handler) {
|
||||
|
||||
if (this.requestInterceptor instanceof AsyncWebRequestInterceptor) {
|
||||
AsyncWebRequestInterceptor asyncInterceptor = (AsyncWebRequestInterceptor) this.requestInterceptor;
|
||||
DispatcherServletWebRequest webRequest = new DispatcherServletWebRequest(request, response);
|
||||
return asyncInterceptor.getAsyncCallable(webRequest);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void postHandleAsyncStarted(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
||||
if (this.requestInterceptor instanceof AsyncWebRequestInterceptor) {
|
||||
AsyncWebRequestInterceptor asyncInterceptor = (AsyncWebRequestInterceptor) this.requestInterceptor;
|
||||
DispatcherServletWebRequest webRequest = new DispatcherServletWebRequest(request, response);
|
||||
asyncInterceptor.postHandleAsyncStarted(webRequest);
|
||||
}
|
||||
}
|
||||
|
||||
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
|
||||
throws Exception {
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package org.springframework.web.servlet;
|
||||
|
||||
import static org.easymock.EasyMock.createMock;
|
||||
import static org.easymock.EasyMock.createStrictMock;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
import static org.easymock.EasyMock.verify;
|
||||
|
|
@ -26,6 +26,7 @@ import org.junit.Before;
|
|||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.web.context.request.async.AbstractDelegatingCallable;
|
||||
|
||||
/**
|
||||
* A test fixture with HandlerExecutionChain and mock handler interceptors.
|
||||
|
|
@ -42,11 +43,11 @@ public class HandlerExecutionChainTests {
|
|||
|
||||
private MockHttpServletResponse response;
|
||||
|
||||
private HandlerInterceptor interceptor1;
|
||||
private AsyncHandlerInterceptor interceptor1;
|
||||
|
||||
private HandlerInterceptor interceptor2;
|
||||
private AsyncHandlerInterceptor interceptor2;
|
||||
|
||||
private HandlerInterceptor interceptor3;
|
||||
private AsyncHandlerInterceptor interceptor3;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
|
|
@ -56,9 +57,9 @@ public class HandlerExecutionChainTests {
|
|||
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.interceptor1 = createStrictMock(AsyncHandlerInterceptor.class);
|
||||
this.interceptor2 = createStrictMock(AsyncHandlerInterceptor.class);
|
||||
this.interceptor3 = createStrictMock(AsyncHandlerInterceptor.class);
|
||||
|
||||
this.chain.addInterceptor(this.interceptor1);
|
||||
this.chain.addInterceptor(this.interceptor2);
|
||||
|
|
@ -91,7 +92,42 @@ public class HandlerExecutionChainTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void earlyExit() throws Exception {
|
||||
public void successAsyncScenario() 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);
|
||||
|
||||
expect(this.interceptor1.getAsyncCallable(request, response, this.handler)).andReturn(new TestAsyncCallable());
|
||||
expect(this.interceptor2.getAsyncCallable(request, response, this.handler)).andReturn(new TestAsyncCallable());
|
||||
expect(this.interceptor3.getAsyncCallable(request, response, this.handler)).andReturn(new TestAsyncCallable());
|
||||
|
||||
this.interceptor1.postHandleAsyncStarted(request, response, this.handler);
|
||||
this.interceptor2.postHandleAsyncStarted(request, response, this.handler);
|
||||
this.interceptor3.postHandleAsyncStarted(request, response, this.handler);
|
||||
|
||||
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.addDelegatingCallables(request, response);
|
||||
this.chain.applyPostHandleAsyncStarted(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 earlyExitInPreHandle() 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);
|
||||
|
||||
|
|
@ -155,4 +191,12 @@ public class HandlerExecutionChainTests {
|
|||
verify(this.interceptor1, this.interceptor2, this.interceptor3);
|
||||
}
|
||||
|
||||
|
||||
private static class TestAsyncCallable extends AbstractDelegatingCallable {
|
||||
|
||||
public Object call() throws Exception {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue