Merge pull request #73 from rstoyanchev/mvc-async

HanderInterceptor and OSIV async request changes
This commit is contained in:
Rossen Stoyanchev 2012-05-04 13:16:18 -07:00
commit 158b3c6af8
12 changed files with 880 additions and 349 deletions

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.orm.hibernate3.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.context.WebApplicationContext; 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.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.filter.OncePerRequestFilter;
@ -168,6 +170,8 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException { throws ServletException, IOException {
AsyncExecutionChain chain = AsyncExecutionChain.getForCurrentRequest(request);
SessionFactory sessionFactory = lookupSessionFactory(request); SessionFactory sessionFactory = lookupSessionFactory(request);
boolean participate = false; boolean participate = false;
@ -180,7 +184,10 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
else { else {
logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter"); logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");
Session session = getSession(sessionFactory); 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 { else {
@ -204,6 +211,9 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
// single session mode // single session mode
SessionHolder sessionHolder = SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory); (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
if (chain.isAsyncStarted()) {
return;
}
logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter"); logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");
closeSession(sessionHolder.getSession(), sessionFactory); closeSession(sessionHolder.getSession(), sessionFactory);
} }
@ -279,4 +289,28 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
SessionFactoryUtils.closeSession(session); 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;
}
};
}
} }

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.HibernateException;
import org.hibernate.Session; import org.hibernate.Session;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateAccessor; import org.springframework.orm.hibernate3.HibernateAccessor;
import org.springframework.orm.hibernate3.SessionFactoryUtils; 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.transaction.support.TransactionSynchronizationManager;
import org.springframework.ui.ModelMap; import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.WebRequest; 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 * 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.orm.hibernate3.SessionFactoryUtils#getSession
* @see org.springframework.transaction.support.TransactionSynchronizationManager * @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> * Suffix that gets appended to the <code>SessionFactory</code>
@ -155,7 +155,8 @@ public class OpenSessionInViewInterceptor extends HibernateAccessor implements W
Session session = SessionFactoryUtils.getSession( Session session = SessionFactoryUtils.getSession(
getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator()); getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());
applyFlushMode(session, false); applyFlushMode(session, false);
TransactionSynchronizationManager.bindResource(getSessionFactory(), new SessionHolder(session)); SessionHolder sessionHolder = new SessionHolder(session);
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
} }
else { else {
// deferred close mode // 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. * Flush the Hibernate <code>Session</code> before view rendering, if necessary.
* <p>Note that this just applies in {@link #isSingleSession() single session mode}! * <p>Note that this just applies in {@link #isSingleSession() single session mode}!

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.orm.hibernate4.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.context.WebApplicationContext; 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.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.filter.OncePerRequestFilter;
@ -102,6 +104,8 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException { throws ServletException, IOException {
AsyncExecutionChain chain = AsyncExecutionChain.getForCurrentRequest(request);
SessionFactory sessionFactory = lookupSessionFactory(request); SessionFactory sessionFactory = lookupSessionFactory(request);
boolean participate = false; boolean participate = false;
@ -112,7 +116,10 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
else { else {
logger.debug("Opening Hibernate Session in OpenSessionInViewFilter"); logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");
Session session = openSession(sessionFactory); 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 { try {
@ -123,6 +130,9 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
if (!participate) { if (!participate) {
SessionHolder sessionHolder = SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory); (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
if (chain.isAsyncStarted()) {
return;
}
logger.debug("Closing Hibernate Session in OpenSessionInViewFilter"); logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
SessionFactoryUtils.closeSession(sessionHolder.getSession()); 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;
}
};
}
} }

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.HibernateException;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.SessionFactory; import org.hibernate.SessionFactory;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.orm.hibernate4.SessionFactoryUtils; 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.transaction.support.TransactionSynchronizationManager;
import org.springframework.ui.ModelMap; import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.WebRequest; 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 * 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.orm.hibernate4.HibernateTransactionManager
* @see org.springframework.transaction.support.TransactionSynchronizationManager * @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> * Suffix that gets appended to the <code>SessionFactory</code>
@ -112,13 +113,47 @@ public class OpenSessionInViewInterceptor implements WebRequestInterceptor {
else { else {
logger.debug("Opening Hibernate Session in OpenSessionInViewInterceptor"); logger.debug("Opening Hibernate Session in OpenSessionInViewInterceptor");
Session session = openSession(); 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) { 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). * Unbind the Hibernate <code>Session</code> from the thread and close it).
* @see org.springframework.transaction.support.TransactionSynchronizationManager * @see org.springframework.transaction.support.TransactionSynchronizationManager

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,23 +16,35 @@
package org.springframework.orm.hibernate3.support; 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.io.IOException;
import java.sql.Connection; import java.sql.Connection;
import java.util.concurrent.Callable;
import javax.servlet.FilterChain; import javax.servlet.FilterChain;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
import javax.transaction.TransactionManager; import javax.transaction.TransactionManager;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.hibernate.FlushMode; import org.hibernate.FlushMode;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.SessionFactory; import org.hibernate.SessionFactory;
import org.hibernate.Transaction; import org.hibernate.Transaction;
import org.hibernate.classic.Session; import org.hibernate.classic.Session;
import org.hibernate.engine.SessionFactoryImplementor; 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.MockFilterConfig;
import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse; 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.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.ServletWebRequest; 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; import org.springframework.web.context.support.StaticWebApplicationContext;
/** /**
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Rossen Stoyanchev
* @since 05.03.2005 * @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 { public void testOpenSessionInViewInterceptorWithSingleSession() throws Exception {
//SessionFactory sf = createMock(SessionFactory.class); SessionFactory sf = createStrictMock(SessionFactory.class);
//Session session = createMock(Session.class); Session session = createStrictMock(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();
OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor(); OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor();
interceptor.setSessionFactory(sf); interceptor.setSessionFactory(sf);
MockServletContext sc = new MockServletContext(); expect(sf.openSession()).andReturn(session);
MockHttpServletRequest request = new MockHttpServletRequest(sc); expect(session.getSessionFactory()).andReturn(sf);
//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);
session.setFlushMode(FlushMode.MANUAL); session.setFlushMode(FlushMode.MANUAL);
sessionControl.setVoidCallable(1); expect(session.getSessionFactory()).andReturn(sf);
sfControl.replay(); expect(session.isOpen()).andReturn(true);
sessionControl.replay(); replay(sf);
interceptor.preHandle(new ServletWebRequest(request)); replay(session);
interceptor.preHandle(this.webRequest);
assertTrue(TransactionSynchronizationManager.hasResource(sf)); assertTrue(TransactionSynchronizationManager.hasResource(sf));
// check that further invocations simply participate // check that further invocations simply participate
interceptor.preHandle(new ServletWebRequest(request)); interceptor.preHandle(this.webRequest);
assertEquals(session, SessionFactoryUtils.getSession(sf, false)); assertEquals(session, SessionFactoryUtils.getSession(sf, false));
interceptor.preHandle(new ServletWebRequest(request)); interceptor.preHandle(this.webRequest);
interceptor.postHandle(new ServletWebRequest(request), null); interceptor.postHandle(this.webRequest, null);
interceptor.afterCompletion(new ServletWebRequest(request), null); interceptor.afterCompletion(this.webRequest, null);
interceptor.postHandle(new ServletWebRequest(request), null); interceptor.postHandle(this.webRequest, null);
interceptor.afterCompletion(new ServletWebRequest(request), null); interceptor.afterCompletion(this.webRequest, null);
interceptor.preHandle(new ServletWebRequest(request)); interceptor.preHandle(this.webRequest);
interceptor.postHandle(new ServletWebRequest(request), null); interceptor.postHandle(this.webRequest, null);
interceptor.afterCompletion(new ServletWebRequest(request), null); interceptor.afterCompletion(this.webRequest, null);
sfControl.verify(); verify(sf);
sessionControl.verify(); verify(session);
reset(sf);
reset(session);
replay(sf);
replay(session);
sfControl.reset(); interceptor.postHandle(this.webRequest, null);
sessionControl.reset();
sfControl.replay();
sessionControl.replay();
interceptor.postHandle(new ServletWebRequest(request), null);
assertTrue(TransactionSynchronizationManager.hasResource(sf)); assertTrue(TransactionSynchronizationManager.hasResource(sf));
sfControl.verify();
sessionControl.verify();
sfControl.reset(); verify(sf);
sessionControl.reset(); verify(session);
session.close(); reset(sf);
sessionControl.setReturnValue(null, 1); reset(session);
sfControl.replay(); expect(session.close()).andReturn(null);
sessionControl.replay(); replay(sf);
interceptor.afterCompletion(new ServletWebRequest(request), null); replay(session);
interceptor.afterCompletion(this.webRequest, null);
assertFalse(TransactionSynchronizationManager.hasResource(sf)); 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 { public void testOpenSessionInViewInterceptorWithSingleSessionAndJtaTm() throws Exception {
MockControl sfControl = MockControl.createControl(SessionFactoryImplementor.class); final SessionFactoryImplementor sf = createStrictMock(SessionFactoryImplementor.class);
final SessionFactoryImplementor sf = (SessionFactoryImplementor) sfControl.getMock(); Session session = createStrictMock(Session.class);
MockControl sessionControl = MockControl.createControl(Session.class);
Session session = (Session) sessionControl.getMock();
MockControl tmControl = MockControl.createControl(TransactionManager.class); TransactionManager tm = createStrictMock(TransactionManager.class);
TransactionManager tm = (TransactionManager) tmControl.getMock(); expect(tm.getTransaction()).andReturn(null);
tm.getTransaction(); expect(tm.getTransaction()).andReturn(null);
tmControl.setReturnValue(null, 2); replay(tm);
OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor(); OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor();
interceptor.setSessionFactory(sf); interceptor.setSessionFactory(sf);
MockServletContext sc = new MockServletContext(); expect(sf.openSession()).andReturn(session);
MockHttpServletRequest request = new MockHttpServletRequest(sc); expect(sf.getTransactionManager()).andReturn(tm);
MockHttpServletResponse response = new MockHttpServletResponse();
sf.getTransactionManager();
sfControl.setReturnValue(tm, 2);
sf.openSession();
sfControl.setReturnValue(session, 1);
session.isOpen();
sessionControl.setReturnValue(true, 1);
session.setFlushMode(FlushMode.MANUAL); session.setFlushMode(FlushMode.MANUAL);
sessionControl.setVoidCallable(1); expect(sf.getTransactionManager()).andReturn(tm);
expect(session.isOpen()).andReturn(true);
tmControl.replay(); replay(sf);
sfControl.replay(); replay(session);
sessionControl.replay();
interceptor.preHandle(new ServletWebRequest(request)); interceptor.preHandle(this.webRequest);
assertTrue(TransactionSynchronizationManager.hasResource(sf)); assertTrue(TransactionSynchronizationManager.hasResource(sf));
// check that further invocations simply participate // check that further invocations simply participate
interceptor.preHandle(new ServletWebRequest(request)); interceptor.preHandle(this.webRequest);
assertEquals(session, SessionFactoryUtils.getSession(sf, false)); assertEquals(session, SessionFactoryUtils.getSession(sf, false));
interceptor.preHandle(new ServletWebRequest(request)); interceptor.preHandle(this.webRequest);
interceptor.postHandle(new ServletWebRequest(request), null); interceptor.postHandle(this.webRequest, null);
interceptor.afterCompletion(new ServletWebRequest(request), null); interceptor.afterCompletion(this.webRequest, null);
interceptor.postHandle(new ServletWebRequest(request), null); interceptor.postHandle(this.webRequest, null);
interceptor.afterCompletion(new ServletWebRequest(request), null); interceptor.afterCompletion(this.webRequest, null);
interceptor.preHandle(new ServletWebRequest(request)); interceptor.preHandle(this.webRequest);
interceptor.postHandle(new ServletWebRequest(request), null); interceptor.postHandle(this.webRequest, null);
interceptor.afterCompletion(new ServletWebRequest(request), null); interceptor.afterCompletion(this.webRequest, null);
sfControl.verify(); verify(sf);
sessionControl.verify(); verify(session);
sfControl.reset(); reset(sf);
sessionControl.reset(); reset(session);
sfControl.replay(); replay(sf);
sessionControl.replay(); replay(session);
interceptor.postHandle(new ServletWebRequest(request), null);
interceptor.postHandle(this.webRequest, null);
assertTrue(TransactionSynchronizationManager.hasResource(sf)); assertTrue(TransactionSynchronizationManager.hasResource(sf));
sfControl.verify();
sessionControl.verify();
sfControl.reset(); verify(sf);
sessionControl.reset(); verify(session);
session.close();
sessionControl.setReturnValue(null, 1); reset(sf);
sfControl.replay(); reset(session);
sessionControl.replay(); expect(session.close()).andReturn(null);
interceptor.afterCompletion(new ServletWebRequest(request), null); replay(sf);
replay(session);
interceptor.afterCompletion(this.webRequest, null);
assertFalse(TransactionSynchronizationManager.hasResource(sf)); assertFalse(TransactionSynchronizationManager.hasResource(sf));
sfControl.verify();
sessionControl.verify(); verify(sf);
verify(session);
} }
@Test
public void testOpenSessionInViewInterceptorWithSingleSessionAndFlush() throws Exception { public void testOpenSessionInViewInterceptorWithSingleSessionAndFlush() throws Exception {
MockControl sfControl = MockControl.createControl(SessionFactory.class); SessionFactory sf = createStrictMock(SessionFactory.class);
final SessionFactory sf = (SessionFactory) sfControl.getMock(); Session session = createStrictMock(Session.class);
MockControl sessionControl = MockControl.createControl(Session.class);
Session session = (Session) sessionControl.getMock();
OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor(); OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor();
interceptor.setSessionFactory(sf); interceptor.setSessionFactory(sf);
interceptor.setFlushMode(HibernateAccessor.FLUSH_AUTO); interceptor.setFlushMode(HibernateAccessor.FLUSH_AUTO);
MockServletContext sc = new MockServletContext(); expect(sf.openSession()).andReturn(session);
MockHttpServletRequest request = new MockHttpServletRequest(sc); expect(session.getSessionFactory()).andReturn(sf);
MockHttpServletResponse response = new MockHttpServletResponse(); replay(sf);
replay(session);
sf.openSession(); interceptor.preHandle(this.webRequest);
sfControl.setReturnValue(session, 1);
session.getSessionFactory();
sessionControl.setReturnValue(sf);
sfControl.replay();
sessionControl.replay();
interceptor.preHandle(new ServletWebRequest(request));
assertTrue(TransactionSynchronizationManager.hasResource(sf)); assertTrue(TransactionSynchronizationManager.hasResource(sf));
sfControl.verify(); verify(sf);
sessionControl.verify(); verify(session);
sfControl.reset(); reset(sf);
sessionControl.reset(); reset(session);
session.flush(); session.flush();
sessionControl.setVoidCallable(1); replay(sf);
sfControl.replay(); replay(session);
sessionControl.replay(); interceptor.postHandle(this.webRequest, null);
interceptor.postHandle(new ServletWebRequest(request), null);
assertTrue(TransactionSynchronizationManager.hasResource(sf)); assertTrue(TransactionSynchronizationManager.hasResource(sf));
sfControl.verify(); verify(sf);
sessionControl.verify(); verify(session);
sfControl.reset(); reset(sf);
sessionControl.reset(); reset(session);
session.close(); expect(session.close()).andReturn(null);
sessionControl.setReturnValue(null, 1); replay(sf);
sfControl.replay(); replay(session);
sessionControl.replay(); interceptor.afterCompletion(this.webRequest, null);
interceptor.afterCompletion(new ServletWebRequest(request), null);
assertFalse(TransactionSynchronizationManager.hasResource(sf)); assertFalse(TransactionSynchronizationManager.hasResource(sf));
sfControl.verify(); verify(sf);
sessionControl.verify(); verify(session);
} }
@Test
public void testOpenSessionInViewInterceptorAndDeferredClose() throws Exception { public void testOpenSessionInViewInterceptorAndDeferredClose() throws Exception {
MockControl sfControl = MockControl.createControl(SessionFactory.class); SessionFactory sf = createStrictMock(SessionFactory.class);
final SessionFactory sf = (SessionFactory) sfControl.getMock(); Session session = createStrictMock(Session.class);
MockControl sessionControl = MockControl.createControl(Session.class);
Session session = (Session) sessionControl.getMock();
OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor(); OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor();
interceptor.setSessionFactory(sf); interceptor.setSessionFactory(sf);
interceptor.setSingleSession(false); interceptor.setSingleSession(false);
MockServletContext sc = new MockServletContext(); expect(sf.openSession()).andReturn(session);
MockHttpServletRequest request = new MockHttpServletRequest(sc); expect(session.getSessionFactory()).andReturn(sf);
MockHttpServletResponse response = new MockHttpServletResponse();
sf.openSession();
sfControl.setReturnValue(session, 1);
session.getSessionFactory();
sessionControl.setReturnValue(sf, 1);
session.setFlushMode(FlushMode.MANUAL); session.setFlushMode(FlushMode.MANUAL);
sessionControl.setVoidCallable(1); replay(sf);
sfControl.replay(); replay(session);
sessionControl.replay();
interceptor.preHandle(new ServletWebRequest(request)); interceptor.preHandle(this.webRequest);
org.hibernate.Session sess = SessionFactoryUtils.getSession(sf, true); org.hibernate.Session sess = SessionFactoryUtils.getSession(sf, true);
SessionFactoryUtils.releaseSession(sess, sf); SessionFactoryUtils.releaseSession(sess, sf);
// check that further invocations simply participate // check that further invocations simply participate
interceptor.preHandle(new ServletWebRequest(request)); interceptor.preHandle(this.webRequest);
interceptor.preHandle(new ServletWebRequest(request)); interceptor.preHandle(this.webRequest);
interceptor.postHandle(new ServletWebRequest(request), null); interceptor.postHandle(this.webRequest, null);
interceptor.afterCompletion(new ServletWebRequest(request), null); interceptor.afterCompletion(this.webRequest, null);
interceptor.postHandle(new ServletWebRequest(request), null); interceptor.postHandle(this.webRequest, null);
interceptor.afterCompletion(new ServletWebRequest(request), null); interceptor.afterCompletion(this.webRequest, null);
interceptor.preHandle(new ServletWebRequest(request)); interceptor.preHandle(this.webRequest);
interceptor.postHandle(new ServletWebRequest(request), null); interceptor.postHandle(this.webRequest, null);
interceptor.afterCompletion(new ServletWebRequest(request), null); interceptor.afterCompletion(this.webRequest, null);
sfControl.verify(); verify(sf);
sessionControl.verify(); verify(session);
sfControl.reset();
sessionControl.reset();
session.close(); reset(sf);
sessionControl.setReturnValue(null, 1); reset(session);
sfControl.replay(); expect(session.close()).andReturn(null);
sessionControl.replay(); replay(sf);
replay(session);
interceptor.postHandle(new ServletWebRequest(request), null); interceptor.postHandle(this.webRequest, null);
interceptor.afterCompletion(new ServletWebRequest(request), null); interceptor.afterCompletion(this.webRequest, null);
sfControl.verify();
sessionControl.verify(); verify(sf);
verify(session);
} }
@Test
public void testOpenSessionInViewFilterWithSingleSession() throws Exception { public void testOpenSessionInViewFilterWithSingleSession() throws Exception {
MockControl sfControl = MockControl.createControl(SessionFactory.class); final SessionFactory sf = createStrictMock(SessionFactory.class);
final SessionFactory sf = (SessionFactory) sfControl.getMock(); Session session = createStrictMock(Session.class);
MockControl sessionControl = MockControl.createControl(Session.class);
Session session = (Session) sessionControl.getMock();
sf.openSession(); expect(sf.openSession()).andReturn(session);
sfControl.setReturnValue(session, 1); expect(session.getSessionFactory()).andReturn(sf);
session.getSessionFactory();
sessionControl.setReturnValue(sf);
session.setFlushMode(FlushMode.MANUAL); session.setFlushMode(FlushMode.MANUAL);
sessionControl.setVoidCallable(1); expect(session.close()).andReturn(null);
session.close(); replay(sf);
sessionControl.setReturnValue(null, 1); replay(session);
sfControl.replay();
sessionControl.replay();
MockControl sf2Control = MockControl.createControl(SessionFactory.class); final SessionFactory sf2 = createStrictMock(SessionFactory.class);
final SessionFactory sf2 = (SessionFactory) sf2Control.getMock(); Session session2 = createStrictMock(Session.class);
MockControl session2Control = MockControl.createControl(Session.class);
Session session2 = (Session) session2Control.getMock();
sf2.openSession(); expect(sf2.openSession()).andReturn(session2);
sf2Control.setReturnValue(session2, 1); expect(session2.getSessionFactory()).andReturn(sf2);
session2.getSessionFactory();
session2Control.setReturnValue(sf);
session2.setFlushMode(FlushMode.AUTO); session2.setFlushMode(FlushMode.AUTO);
session2Control.setVoidCallable(1); expect(session2.close()).andReturn(null);
session2.close(); replay(sf2);
session2Control.setReturnValue(null, 1); replay(session2);
sf2Control.replay();
session2Control.replay();
MockServletContext sc = new MockServletContext();
StaticWebApplicationContext wac = new StaticWebApplicationContext(); StaticWebApplicationContext wac = new StaticWebApplicationContext();
wac.setServletContext(sc); wac.setServletContext(sc);
wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf); wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf);
wac.getDefaultListableBeanFactory().registerSingleton("mySessionFactory", sf2); wac.getDefaultListableBeanFactory().registerSingleton("mySessionFactory", sf2);
wac.refresh(); wac.refresh();
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); 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 filterConfig = new MockFilterConfig(wac.getServletContext(), "filter");
MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2"); MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2");
@ -378,44 +424,112 @@ public class OpenSessionInViewTests extends TestCase {
assertFalse(TransactionSynchronizationManager.hasResource(sf)); assertFalse(TransactionSynchronizationManager.hasResource(sf));
assertFalse(TransactionSynchronizationManager.hasResource(sf2)); assertFalse(TransactionSynchronizationManager.hasResource(sf2));
filter2.doFilter(request, response, filterChain3); filter2.doFilter(this.request, this.response, filterChain3);
assertFalse(TransactionSynchronizationManager.hasResource(sf)); assertFalse(TransactionSynchronizationManager.hasResource(sf));
assertFalse(TransactionSynchronizationManager.hasResource(sf2)); assertFalse(TransactionSynchronizationManager.hasResource(sf2));
assertNotNull(request.getAttribute("invoked")); assertNotNull(this.request.getAttribute("invoked"));
sfControl.verify(); verify(sf);
sessionControl.verify(); verify(session);
sf2Control.verify(); verify(sf2);
session2Control.verify(); verify(session2);
wac.close(); wac.close();
} }
public void testOpenSessionInViewFilterWithSingleSessionAndPreBoundSession() throws Exception { @Test
MockControl sfControl = MockControl.createControl(SessionFactory.class); public void testOpenSessionInViewFilterWithSingleSessionAsyncScenario() throws Exception {
final SessionFactory sf = (SessionFactory) sfControl.getMock(); final SessionFactory sf = createStrictMock(SessionFactory.class);
MockControl sessionControl = MockControl.createControl(Session.class); Session session = createStrictMock(Session.class);
Session session = (Session) sessionControl.getMock();
sf.openSession(); expect(sf.openSession()).andReturn(session);
sfControl.setReturnValue(session, 1); expect(session.getSessionFactory()).andReturn(sf);
session.getSessionFactory();
sessionControl.setReturnValue(sf);
session.setFlushMode(FlushMode.MANUAL); session.setFlushMode(FlushMode.MANUAL);
sessionControl.setVoidCallable(1); replay(sf);
session.close(); replay(session);
sessionControl.setReturnValue(null, 1);
sfControl.replay(); StaticWebApplicationContext wac = new StaticWebApplicationContext();
sessionControl.replay(); 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(); StaticWebApplicationContext wac = new StaticWebApplicationContext();
wac.setServletContext(sc); wac.setServletContext(sc);
wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf); wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf);
wac.refresh(); wac.refresh();
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); 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 filterConfig = new MockFilterConfig(wac.getServletContext(), "filter");
MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2"); MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2");
@ -424,7 +538,7 @@ public class OpenSessionInViewTests extends TestCase {
OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor(); OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor();
interceptor.setSessionFactory(sf); interceptor.setSessionFactory(sf);
interceptor.preHandle(new ServletWebRequest(request)); interceptor.preHandle(this.webRequest);
final OpenSessionInViewFilter filter = new OpenSessionInViewFilter(); final OpenSessionInViewFilter filter = new OpenSessionInViewFilter();
filter.init(filterConfig); filter.init(filterConfig);
@ -437,74 +551,57 @@ public class OpenSessionInViewTests extends TestCase {
}; };
assertTrue(TransactionSynchronizationManager.hasResource(sf)); assertTrue(TransactionSynchronizationManager.hasResource(sf));
filter.doFilter(request, response, filterChain); filter.doFilter(this.request, this.response, filterChain);
assertTrue(TransactionSynchronizationManager.hasResource(sf)); assertTrue(TransactionSynchronizationManager.hasResource(sf));
assertNotNull(request.getAttribute("invoked")); assertNotNull(this.request.getAttribute("invoked"));
interceptor.postHandle(new ServletWebRequest(request), null); interceptor.postHandle(this.webRequest, null);
interceptor.afterCompletion(new ServletWebRequest(request), null); interceptor.afterCompletion(this.webRequest, null);
sfControl.verify(); verify(sf);
sessionControl.verify(); verify(session);
wac.close(); wac.close();
} }
@Test
public void testOpenSessionInViewFilterWithDeferredClose() throws Exception { public void testOpenSessionInViewFilterWithDeferredClose() throws Exception {
MockControl sfControl = MockControl.createControl(SessionFactory.class); final SessionFactory sf = createStrictMock(SessionFactory.class);
final SessionFactory sf = (SessionFactory) sfControl.getMock(); final Session session = createStrictMock(Session.class);
final MockControl sessionControl = MockControl.createControl(Session.class);
final Session session = (Session) sessionControl.getMock();
sf.openSession(); expect(sf.openSession()).andReturn(session);
sfControl.setReturnValue(session, 1); expect(session.getSessionFactory()).andReturn(sf);
session.getSessionFactory(); expect(session.getFlushMode()).andReturn(FlushMode.MANUAL);
sessionControl.setReturnValue(sf);
session.getFlushMode();
sessionControl.setReturnValue(FlushMode.MANUAL, 1);
session.setFlushMode(FlushMode.MANUAL); session.setFlushMode(FlushMode.MANUAL);
sessionControl.setVoidCallable(1); replay(sf);
sfControl.replay(); replay(session);
sessionControl.replay();
MockControl sf2Control = MockControl.createControl(SessionFactory.class); final SessionFactory sf2 = createStrictMock(SessionFactory.class);
final SessionFactory sf2 = (SessionFactory) sf2Control.getMock(); final Session session2 = createStrictMock(Session.class);
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();
sf2.openSession(); Transaction tx = createStrictMock(Transaction.class);
sf2Control.setReturnValue(session2, 1); Connection con = createStrictMock(Connection.class);
session2.beginTransaction();
session2Control.setReturnValue(tx, 1); expect(sf2.openSession()).andReturn(session2);
session2.connection(); expect(session2.connection()).andReturn(con);
session2Control.setReturnValue(con, 2); expect(session2.beginTransaction()).andReturn(tx);
expect(session2.isConnected()).andReturn(true);
expect(session2.connection()).andReturn(con);
tx.commit(); tx.commit();
txControl.setVoidCallable(1); expect(con.isReadOnly()).andReturn(false);
session2.isConnected();
session2Control.setReturnValue(true, 1);
con.isReadOnly();
conControl.setReturnValue(false, 1);
session2.setFlushMode(FlushMode.MANUAL); session2.setFlushMode(FlushMode.MANUAL);
session2Control.setVoidCallable(1);
sf2Control.replay(); replay(sf2);
session2Control.replay(); replay(session2);
txControl.replay(); replay(tx);
conControl.replay(); replay(con);
MockServletContext sc = new MockServletContext();
StaticWebApplicationContext wac = new StaticWebApplicationContext(); StaticWebApplicationContext wac = new StaticWebApplicationContext();
wac.setServletContext(sc); wac.setServletContext(sc);
wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf); wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf);
wac.getDefaultListableBeanFactory().registerSingleton("mySessionFactory", sf2); wac.getDefaultListableBeanFactory().registerSingleton("mySessionFactory", sf2);
wac.refresh(); wac.refresh();
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); 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 filterConfig = new MockFilterConfig(wac.getServletContext(), "filter");
MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2"); MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2");
@ -526,12 +623,11 @@ public class OpenSessionInViewTests extends TestCase {
SessionFactoryUtils.releaseSession(sess, sf); SessionFactoryUtils.releaseSession(sess, sf);
tm.commit(ts); tm.commit(ts);
sessionControl.verify(); verify(session);
sessionControl.reset(); reset(session);
session.close(); expect(session.close()).andReturn(null);
sessionControl.setReturnValue(null, 1); replay(session);
sessionControl.replay();
servletRequest.setAttribute("invoked", Boolean.TRUE); servletRequest.setAttribute("invoked", Boolean.TRUE);
} }
@ -545,12 +641,11 @@ public class OpenSessionInViewTests extends TestCase {
TransactionStatus ts = tm.getTransaction(new DefaultTransactionDefinition()); TransactionStatus ts = tm.getTransaction(new DefaultTransactionDefinition());
tm.commit(ts); tm.commit(ts);
session2Control.verify(); verify(session2);
session2Control.reset(); reset(session2);
session2.close(); expect(session2.close()).andReturn(null);
session2Control.setReturnValue(null, 1); replay(session2);
session2Control.replay();
filter.doFilter(servletRequest, servletResponse, filterChain); filter.doFilter(servletRequest, servletResponse, filterChain);
} }
@ -558,44 +653,48 @@ public class OpenSessionInViewTests extends TestCase {
FilterChain filterChain3 = new PassThroughFilterChain(filter2, filterChain2); FilterChain filterChain3 = new PassThroughFilterChain(filter2, filterChain2);
filter2.doFilter(request, response, filterChain3); filter2.doFilter(this.request, this.response, filterChain3);
assertNotNull(request.getAttribute("invoked")); assertNotNull(this.request.getAttribute("invoked"));
sfControl.verify(); verify(sf);
sessionControl.verify(); verify(session);
sf2Control.verify();
session2Control.verify(); verify(sf2);
txControl.verify(); verify(session2);
conControl.verify(); verify(tx);
verify(con);
wac.close(); wac.close();
} }
@Test
public void testOpenSessionInViewFilterWithDeferredCloseAndAlreadyActiveDeferredClose() throws Exception { public void testOpenSessionInViewFilterWithDeferredCloseAndAlreadyActiveDeferredClose() throws Exception {
MockControl sfControl = MockControl.createControl(SessionFactory.class); final SessionFactory sf = createStrictMock(SessionFactory.class);
final SessionFactory sf = (SessionFactory) sfControl.getMock(); final Session session = createStrictMock(Session.class);
final MockControl sessionControl = MockControl.createControl(Session.class);
final Session session = (Session) sessionControl.getMock();
sf.openSession(); expect(sf.openSession()).andReturn(session);
sfControl.setReturnValue(session, 1); expect(session.getSessionFactory()).andReturn(sf);
session.getSessionFactory(); expect(session.getFlushMode()).andReturn(FlushMode.MANUAL);
sessionControl.setReturnValue(sf);
session.getFlushMode();
sessionControl.setReturnValue(FlushMode.MANUAL, 1);
session.setFlushMode(FlushMode.MANUAL); session.setFlushMode(FlushMode.MANUAL);
sessionControl.setVoidCallable(1); replay(sf);
sfControl.replay(); replay(session);
sessionControl.replay();
// 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(); StaticWebApplicationContext wac = new StaticWebApplicationContext();
wac.setServletContext(sc); wac.setServletContext(sc);
wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf); wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf);
wac.refresh(); wac.refresh();
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); 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 filterConfig = new MockFilterConfig(wac.getServletContext(), "filter");
MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2"); MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2");
@ -607,7 +706,7 @@ public class OpenSessionInViewTests extends TestCase {
interceptor.setSessionFactory(sf); interceptor.setSessionFactory(sf);
interceptor.setSingleSession(false); interceptor.setSingleSession(false);
interceptor.preHandle(new ServletWebRequest(request)); interceptor.preHandle(webRequest);
final OpenSessionInViewFilter filter = new OpenSessionInViewFilter(); final OpenSessionInViewFilter filter = new OpenSessionInViewFilter();
filter.init(filterConfig); filter.init(filterConfig);
@ -623,15 +722,14 @@ public class OpenSessionInViewTests extends TestCase {
SessionFactoryUtils.releaseSession(sess, sf); SessionFactoryUtils.releaseSession(sess, sf);
tm.commit(ts); tm.commit(ts);
sessionControl.verify(); verify(session);
sessionControl.reset(); reset(session);
try { try {
session.close(); expect(session.close()).andReturn(null);
} }
catch (HibernateException ex) { catch (HibernateException ex) {
} }
sessionControl.setReturnValue(null, 1); replay(session);
sessionControl.replay();
servletRequest.setAttribute("invoked", Boolean.TRUE); servletRequest.setAttribute("invoked", Boolean.TRUE);
} }
@ -644,16 +742,25 @@ public class OpenSessionInViewTests extends TestCase {
} }
}; };
filter.doFilter(request, response, filterChain2); filter.doFilter(this.request, this.response, filterChain2);
assertNotNull(request.getAttribute("invoked")); assertNotNull(this.request.getAttribute("invoked"));
interceptor.postHandle(new ServletWebRequest(request), null); interceptor.postHandle(webRequest, null);
interceptor.afterCompletion(new ServletWebRequest(request), null); interceptor.afterCompletion(webRequest, null);
sfControl.verify(); verify(sf);
sessionControl.verify(); verify(session);
wac.close(); wac.close();
} }
@SuppressWarnings("serial")
private static class SyncTaskExecutor extends SimpleAsyncTaskExecutor {
@Override
public void execute(Runnable task, long startTimeout) {
task.run();
}
}
} }

View File

@ -25,6 +25,8 @@ import javax.servlet.ServletRequest;
import org.springframework.core.task.AsyncTaskExecutor; import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.SimpleAsyncTaskExecutor; import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.util.Assert; 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; import org.springframework.web.context.request.async.DeferredResult.DeferredResultHandler;
/** /**
@ -77,6 +79,20 @@ public final class AsyncExecutionChain {
return chain; 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. * Provide an instance of an AsyncWebRequest.
* This property must be set before async request processing can begin. * This property must be set before async request processing can begin.

View File

@ -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);
}

View File

@ -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);
}

View File

@ -941,6 +941,8 @@ public class DispatcherServlet extends FrameworkServlet {
return; return;
} }
mappedHandler.addDelegatingCallables(processedRequest, response);
asyncChain.addDelegatingCallable( asyncChain.addDelegatingCallable(
getDispatchAsyncCallable(mappedHandler, request, response, processedRequest)); getDispatchAsyncCallable(mappedHandler, request, response, processedRequest));
@ -948,6 +950,7 @@ public class DispatcherServlet extends FrameworkServlet {
mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncChain.isAsyncStarted()) { if (asyncChain.isAsyncStarted()) {
mappedHandler.applyPostHandleAsyncStarted(processedRequest, response);
logger.debug("Exiting request thread and leaving the response open"); logger.debug("Exiting request thread and leaving the response open");
return; return;
} }

View File

@ -26,6 +26,7 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.async.AsyncExecutionChain;
/** /**
* Handler execution chain, consisting of handler object and any handler interceptors. * 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) void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv)
throws Exception { 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. * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
* Will just invoke afterCompletion for all interceptors whose preHandle invocation * Will just invoke afterCompletion for all interceptors whose preHandle invocation

View File

@ -21,7 +21,9 @@ import javax.servlet.http.HttpServletResponse;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.web.context.request.WebRequestInterceptor; 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; 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.context.request.WebRequestInterceptor
* @see org.springframework.web.servlet.HandlerInterceptor * @see org.springframework.web.servlet.HandlerInterceptor
*/ */
public class WebRequestHandlerInterceptorAdapter implements HandlerInterceptor { public class WebRequestHandlerInterceptorAdapter implements AsyncHandlerInterceptor {
private final WebRequestInterceptor requestInterceptor; private final WebRequestInterceptor requestInterceptor;
@ -55,6 +57,25 @@ public class WebRequestHandlerInterceptorAdapter implements HandlerInterceptor {
return true; 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) public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception { throws Exception {

View File

@ -16,7 +16,7 @@
package org.springframework.web.servlet; 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.expect;
import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify; import static org.easymock.EasyMock.verify;
@ -26,6 +26,7 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.context.request.async.AbstractDelegatingCallable;
/** /**
* A test fixture with HandlerExecutionChain and mock handler interceptors. * A test fixture with HandlerExecutionChain and mock handler interceptors.
@ -42,11 +43,11 @@ public class HandlerExecutionChainTests {
private MockHttpServletResponse response; private MockHttpServletResponse response;
private HandlerInterceptor interceptor1; private AsyncHandlerInterceptor interceptor1;
private HandlerInterceptor interceptor2; private AsyncHandlerInterceptor interceptor2;
private HandlerInterceptor interceptor3; private AsyncHandlerInterceptor interceptor3;
@Before @Before
public void setup() { public void setup() {
@ -56,9 +57,9 @@ public class HandlerExecutionChainTests {
this.handler = new Object(); this.handler = new Object();
this.chain = new HandlerExecutionChain(this.handler); this.chain = new HandlerExecutionChain(this.handler);
this.interceptor1 = createMock(HandlerInterceptor.class); this.interceptor1 = createStrictMock(AsyncHandlerInterceptor.class);
this.interceptor2 = createMock(HandlerInterceptor.class); this.interceptor2 = createStrictMock(AsyncHandlerInterceptor.class);
this.interceptor3 = createMock(HandlerInterceptor.class); this.interceptor3 = createStrictMock(AsyncHandlerInterceptor.class);
this.chain.addInterceptor(this.interceptor1); this.chain.addInterceptor(this.interceptor1);
this.chain.addInterceptor(this.interceptor2); this.chain.addInterceptor(this.interceptor2);
@ -91,7 +92,42 @@ public class HandlerExecutionChainTests {
} }
@Test @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.interceptor1.preHandle(this.request, this.response, this.handler)).andReturn(true);
expect(this.interceptor2.preHandle(this.request, this.response, this.handler)).andReturn(false); 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); verify(this.interceptor1, this.interceptor2, this.interceptor3);
} }
private static class TestAsyncCallable extends AbstractDelegatingCallable {
public Object call() throws Exception {
return null;
}
}
} }