Update remaining filter with async support

Issue: SPR-9433
This commit is contained in:
Rossen Stoyanchev
2012-08-17 13:04:38 -04:00
parent cdab04a032
commit 4f55518290
10 changed files with 389 additions and 127 deletions

View File

@@ -166,7 +166,6 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
return this.flushMode;
}
/**
* The default value is "true" so that the filter may re-bind the opened
* {@code Session} to each asynchronously dispatched thread and postpone
@@ -186,6 +185,7 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
boolean participate = false;
WebAsyncManager asyncManager = AsyncWebUtils.getAsyncManager(request);
boolean isFirstRequest = !isAsyncDispatch(request);
String key = getAlreadyFilteredAttributeName();
if (isSingleSession()) {
@@ -195,7 +195,7 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
participate = true;
}
else {
if (!isAsyncDispatch(request) || !asyncManager.initializeAsyncThread(key)) {
if (isFirstRequest || !asyncManager.initializeAsyncThread(key)) {
logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");
Session session = getSession(sessionFactory);
SessionHolder sessionHolder = new SessionHolder(session);
@@ -240,19 +240,6 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
}
}
private WebAsyncThreadInitializer createAsyncThreadInitializer(final SessionFactory sessionFactory,
final SessionHolder sessionHolder) {
return new WebAsyncThreadInitializer() {
public void initialize() {
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
}
public void reset() {
TransactionSynchronizationManager.unbindResource(sessionFactory);
}
};
}
/**
* Look up the SessionFactory that this filter should use,
* taking the current HTTP request as argument.
@@ -317,4 +304,17 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
SessionFactoryUtils.closeSession(session);
}
private WebAsyncThreadInitializer createAsyncThreadInitializer(final SessionFactory sessionFactory,
final SessionHolder sessionHolder) {
return new WebAsyncThreadInitializer() {
public void initialize() {
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
}
public void reset() {
TransactionSynchronizationManager.unbindResource(sessionFactory);
}
};
}
}

View File

@@ -99,7 +99,6 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
return this.sessionFactoryBeanName;
}
/**
* The default value is "true" so that the filter may re-bind the opened
* {@code Session} to each asynchronously dispatched thread and postpone
@@ -119,6 +118,7 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
boolean participate = false;
WebAsyncManager asyncManager = AsyncWebUtils.getAsyncManager(request);
boolean isFirstRequest = !isAsyncDispatch(request);
String key = getAlreadyFilteredAttributeName();
if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
@@ -126,7 +126,7 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
participate = true;
}
else {
if (!isAsyncDispatch(request) || !asyncManager.initializeAsyncThread(key)) {
if (isFirstRequest || !asyncManager.initializeAsyncThread(key)) {
logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");
Session session = openSession(sessionFactory);
SessionHolder sessionHolder = new SessionHolder(session);
@@ -153,19 +153,6 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
}
}
private WebAsyncThreadInitializer createAsyncThreadInitializer(final SessionFactory sessionFactory,
final SessionHolder sessionHolder) {
return new WebAsyncThreadInitializer() {
public void initialize() {
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
}
public void reset() {
TransactionSynchronizationManager.unbindResource(sessionFactory);
}
};
}
/**
* Look up the SessionFactory that this filter should use,
* taking the current HTTP request as argument.
@@ -214,4 +201,17 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
}
}
private WebAsyncThreadInitializer createAsyncThreadInitializer(final SessionFactory sessionFactory,
final SessionHolder sessionHolder) {
return new WebAsyncThreadInitializer() {
public void initialize() {
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
}
public void reset() {
TransactionSynchronizationManager.unbindResource(sessionFactory);
}
};
}
}

View File

@@ -105,9 +105,9 @@ public class OpenSessionInViewInterceptor implements AsyncWebRequestInterceptor
*/
public void preHandle(WebRequest request) throws DataAccessException {
WebAsyncManager asyncManager = AsyncWebUtils.getAsyncManager(request);
String participateAttributeName = getParticipateAttributeName();
WebAsyncManager asyncManager = AsyncWebUtils.getAsyncManager(request);
if (asyncManager.hasConcurrentResult()) {
if (asyncManager.initializeAsyncThread(participateAttributeName)) {
return;
@@ -148,12 +148,6 @@ public class OpenSessionInViewInterceptor implements AsyncWebRequestInterceptor
}
}
public void afterConcurrentHandlingStarted(WebRequest request) {
if (!decrementParticipateCount(request)) {
TransactionSynchronizationManager.unbindResource(getSessionFactory());
}
}
private boolean decrementParticipateCount(WebRequest request) {
String participateAttributeName = getParticipateAttributeName();
Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
@@ -170,6 +164,12 @@ public class OpenSessionInViewInterceptor implements AsyncWebRequestInterceptor
return true;
}
public void afterConcurrentHandlingStarted(WebRequest request) {
if (!decrementParticipateCount(request)) {
TransactionSynchronizationManager.unbindResource(getSessionFactory());
}
}
/**
* Open a Session for the SessionFactory that this interceptor uses.
* <p>The default implementation delegates to the

View File

@@ -17,6 +17,7 @@
package org.springframework.orm.jpa.support;
import java.io.IOException;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceException;
@@ -31,6 +32,9 @@ import org.springframework.orm.jpa.EntityManagerHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.StringUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.async.AsyncWebUtils;
import org.springframework.web.context.request.async.WebAsyncManager;
import org.springframework.web.context.request.async.WebAsyncManager.WebAsyncThreadInitializer;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.OncePerRequestFilter;
@@ -119,6 +123,15 @@ public class OpenEntityManagerInViewFilter extends OncePerRequestFilter {
return this.persistenceUnitName;
}
/**
* The default value is "true" so that the filter may re-bind the opened
* {@code EntityManager} to each asynchronously dispatched thread and postpone
* closing it until the very last asynchronous dispatch.
*/
@Override
protected boolean shouldFilterAsyncDispatches() {
return true;
}
@Override
protected void doFilterInternal(
@@ -128,18 +141,28 @@ public class OpenEntityManagerInViewFilter extends OncePerRequestFilter {
EntityManagerFactory emf = lookupEntityManagerFactory(request);
boolean participate = false;
WebAsyncManager asyncManager = AsyncWebUtils.getAsyncManager(request);
boolean isFirstRequest = !isAsyncDispatch(request);
String key = getAlreadyFilteredAttributeName();
if (TransactionSynchronizationManager.hasResource(emf)) {
// Do not modify the EntityManager: just set the participate flag.
participate = true;
}
else {
logger.debug("Opening JPA EntityManager in OpenEntityManagerInViewFilter");
try {
EntityManager em = createEntityManager(emf);
TransactionSynchronizationManager.bindResource(emf, new EntityManagerHolder(em));
}
catch (PersistenceException ex) {
throw new DataAccessResourceFailureException("Could not create JPA EntityManager", ex);
if (isFirstRequest || !asyncManager.initializeAsyncThread(key)) {
logger.debug("Opening JPA EntityManager in OpenEntityManagerInViewFilter");
try {
EntityManager em = createEntityManager(emf);
EntityManagerHolder emHolder = new EntityManagerHolder(em);
TransactionSynchronizationManager.bindResource(emf, emHolder);
WebAsyncThreadInitializer initializer = createAsyncThreadInitializer(emf, emHolder);
asyncManager.registerAsyncThreadInitializer(key, initializer);
}
catch (PersistenceException ex) {
throw new DataAccessResourceFailureException("Could not create JPA EntityManager", ex);
}
}
}
@@ -151,8 +174,10 @@ public class OpenEntityManagerInViewFilter extends OncePerRequestFilter {
if (!participate) {
EntityManagerHolder emHolder = (EntityManagerHolder)
TransactionSynchronizationManager.unbindResource(emf);
logger.debug("Closing JPA EntityManager in OpenEntityManagerInViewFilter");
EntityManagerFactoryUtils.closeEntityManager(emHolder.getEntityManager());
if (isLastRequestThread(request)) {
logger.debug("Closing JPA EntityManager in OpenEntityManagerInViewFilter");
EntityManagerFactoryUtils.closeEntityManager(emHolder.getEntityManager());
}
}
}
}
@@ -205,4 +230,17 @@ public class OpenEntityManagerInViewFilter extends OncePerRequestFilter {
return emf.createEntityManager();
}
private WebAsyncThreadInitializer createAsyncThreadInitializer(final EntityManagerFactory emFactory,
final EntityManagerHolder emHolder) {
return new WebAsyncThreadInitializer() {
public void initialize() {
TransactionSynchronizationManager.bindResource(emFactory, emHolder);
}
public void reset() {
TransactionSynchronizationManager.unbindResource(emFactory);
}
};
}
}

View File

@@ -22,12 +22,15 @@ import javax.persistence.PersistenceException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.orm.jpa.EntityManagerFactoryAccessor;
import org.springframework.orm.jpa.EntityManagerHolder;
import org.springframework.orm.jpa.EntityManagerFactoryUtils;
import org.springframework.orm.jpa.EntityManagerHolder;
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.AsyncWebRequestInterceptor;
import org.springframework.web.context.request.async.AsyncWebUtils;
import org.springframework.web.context.request.async.WebAsyncManager;
import org.springframework.web.context.request.async.WebAsyncManager.WebAsyncThreadInitializer;
/**
* Spring web request interceptor that binds a JPA EntityManager to the
@@ -56,7 +59,7 @@ import org.springframework.web.context.request.WebRequestInterceptor;
* @see org.springframework.orm.jpa.SharedEntityManagerCreator
* @see org.springframework.transaction.support.TransactionSynchronizationManager
*/
public class OpenEntityManagerInViewInterceptor extends EntityManagerFactoryAccessor implements WebRequestInterceptor {
public class OpenEntityManagerInViewInterceptor extends EntityManagerFactoryAccessor implements AsyncWebRequestInterceptor {
/**
* Suffix that gets appended to the EntityManagerFactory toString
@@ -68,9 +71,18 @@ public class OpenEntityManagerInViewInterceptor extends EntityManagerFactoryAcce
public void preHandle(WebRequest request) throws DataAccessException {
String participateAttributeName = getParticipateAttributeName();
WebAsyncManager asyncManager = AsyncWebUtils.getAsyncManager(request);
if (asyncManager.hasConcurrentResult()) {
if (asyncManager.initializeAsyncThread(participateAttributeName)) {
return;
}
}
if (TransactionSynchronizationManager.hasResource(getEntityManagerFactory())) {
// do not modify the EntityManager: just mark the request accordingly
String participateAttributeName = getParticipateAttributeName();
Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
int newCount = (count != null ? count + 1 : 1);
request.setAttribute(getParticipateAttributeName(), newCount, WebRequest.SCOPE_REQUEST);
@@ -79,7 +91,11 @@ public class OpenEntityManagerInViewInterceptor extends EntityManagerFactoryAcce
logger.debug("Opening JPA EntityManager in OpenEntityManagerInViewInterceptor");
try {
EntityManager em = createEntityManager();
TransactionSynchronizationManager.bindResource(getEntityManagerFactory(), new EntityManagerHolder(em));
EntityManagerHolder emHolder = new EntityManagerHolder(em);
TransactionSynchronizationManager.bindResource(getEntityManagerFactory(), emHolder);
WebAsyncThreadInitializer asyncThreadInitializer = createThreadInitializer(emHolder);
asyncManager.registerAsyncThreadInitializer(participateAttributeName, asyncThreadInitializer);
}
catch (PersistenceException ex) {
throw new DataAccessResourceFailureException("Could not create JPA EntityManager", ex);
@@ -91,18 +107,7 @@ public class OpenEntityManagerInViewInterceptor extends EntityManagerFactoryAcce
}
public void afterCompletion(WebRequest request, Exception ex) throws DataAccessException {
String participateAttributeName = getParticipateAttributeName();
Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
if (count != null) {
// Do not modify the EntityManager: just clear the marker.
if (count > 1) {
request.setAttribute(participateAttributeName, count - 1, WebRequest.SCOPE_REQUEST);
}
else {
request.removeAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
}
}
else {
if (!decrementParticipateCount(request)) {
EntityManagerHolder emHolder = (EntityManagerHolder)
TransactionSynchronizationManager.unbindResource(getEntityManagerFactory());
logger.debug("Closing JPA EntityManager in OpenEntityManagerInViewInterceptor");
@@ -110,6 +115,28 @@ public class OpenEntityManagerInViewInterceptor extends EntityManagerFactoryAcce
}
}
private boolean decrementParticipateCount(WebRequest request) {
String participateAttributeName = getParticipateAttributeName();
Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
if (count == null) {
return false;
}
// Do not modify the Session: just clear the marker.
if (count > 1) {
request.setAttribute(participateAttributeName, count - 1, WebRequest.SCOPE_REQUEST);
}
else {
request.removeAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
}
return true;
}
public void afterConcurrentHandlingStarted(WebRequest request) {
if (!decrementParticipateCount(request)) {
TransactionSynchronizationManager.unbindResource(getEntityManagerFactory());
}
}
/**
* Return the name of the request attribute that identifies that a request is
* already filtered. Default implementation takes the toString representation
@@ -120,4 +147,15 @@ public class OpenEntityManagerInViewInterceptor extends EntityManagerFactoryAcce
return getEntityManagerFactory().toString() + PARTICIPATE_SUFFIX;
}
private WebAsyncThreadInitializer createThreadInitializer(final EntityManagerHolder emHolder) {
return new WebAsyncThreadInitializer() {
public void initialize() {
TransactionSynchronizationManager.bindResource(getEntityManagerFactory(), emHolder);
}
public void reset() {
TransactionSynchronizationManager.unbindResource(getEntityManagerFactory());
}
};
}
}

View File

@@ -460,7 +460,7 @@ public class OpenSessionInViewTests {
final SessionFactory sf = createStrictMock(SessionFactory.class);
Session session = createStrictMock(Session.class);
// Initial request during which concurrent handler execution starts..
// Initial request during which concurrent handling starts..
expect(sf.openSession()).andReturn(session);
expect(session.getSessionFactory()).andReturn(sf);
@@ -516,11 +516,10 @@ public class OpenSessionInViewTests {
reset(session);
reset(asyncWebRequest);
// Async dispatch after concurrent handler execution results ready..
// Async dispatch after concurrent handling produces result ...
expect(session.close()).andReturn(null);
expect(asyncWebRequest.isAsyncStarted()).andReturn(false);
expectLastCall().anyTimes();
expect(asyncWebRequest.isAsyncStarted()).andReturn(false).anyTimes();
replay(sf);
replay(session);

View File

@@ -16,7 +16,21 @@
package org.springframework.orm.jpa.support;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.createStrictMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
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 java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicInteger;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.servlet.FilterChain;
@@ -25,7 +39,6 @@ import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.mock.web.MockFilterConfig;
import org.springframework.mock.web.MockHttpServletRequest;
@@ -36,6 +49,9 @@ import org.springframework.orm.jpa.JpaTemplate;
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.AsyncWebRequest;
import org.springframework.web.context.request.async.AsyncWebUtils;
import org.springframework.web.context.request.async.WebAsyncManager;
import org.springframework.web.context.support.StaticWebApplicationContext;
/**
@@ -44,8 +60,6 @@ import org.springframework.web.context.support.StaticWebApplicationContext;
* @author Chris Beams
*/
public class OpenEntityManagerInViewTests extends TestCase {
private MockControl factoryControl, managerControl;
private EntityManager manager;
@@ -56,15 +70,13 @@ public class OpenEntityManagerInViewTests extends TestCase {
@Override
protected void setUp() throws Exception {
factoryControl = MockControl.createControl(EntityManagerFactory.class);
factory = (EntityManagerFactory) factoryControl.getMock();
managerControl = MockControl.createControl(EntityManager.class);
manager = (EntityManager) managerControl.getMock();
factory = createMock(EntityManagerFactory.class);
manager = createMock(EntityManager.class);
template = new JpaTemplate(factory);
template.afterPropertiesSet();
factoryControl.expectAndReturn(factory.createEntityManager(), manager);
expect(factory.createEntityManager()).andReturn(manager);
}
@Override
@@ -82,8 +94,7 @@ public class OpenEntityManagerInViewTests extends TestCase {
MockServletContext sc = new MockServletContext();
MockHttpServletRequest request = new MockHttpServletRequest(sc);
managerControl.replay();
factoryControl.replay();
replay(manager, factory);
interceptor.preHandle(new ServletWebRequest(request));
assertTrue(TransactionSynchronizationManager.hasResource(factory));
@@ -102,55 +113,131 @@ public class OpenEntityManagerInViewTests extends TestCase {
interceptor.postHandle(new ServletWebRequest(request), null);
interceptor.afterCompletion(new ServletWebRequest(request), null);
factoryControl.verify();
managerControl.verify();
verify(manager, factory);
managerControl.reset();
factoryControl.reset();
managerControl.replay();
factoryControl.replay();
reset(manager, factory);
replay(manager, factory);
interceptor.postHandle(new ServletWebRequest(request), null);
assertTrue(TransactionSynchronizationManager.hasResource(factory));
factoryControl.verify();
managerControl.verify();
verify(manager, factory);
managerControl.reset();
factoryControl.reset();
reset(manager, factory);
managerControl.expectAndReturn(manager.isOpen(), true);
expect(manager.isOpen()).andReturn(true);
manager.close();
managerControl.replay();
factoryControl.replay();
replay(manager, factory);
interceptor.afterCompletion(new ServletWebRequest(request), null);
assertFalse(TransactionSynchronizationManager.hasResource(factory));
factoryControl.verify();
managerControl.verify();
verify(manager, factory);
}
public void testOpenEntityManagerInViewInterceptorAsyncScenario() throws Exception {
// Initial request thread
OpenEntityManagerInViewInterceptor interceptor = new OpenEntityManagerInViewInterceptor();
interceptor.setEntityManagerFactory(factory);
MockServletContext sc = new MockServletContext();
MockHttpServletRequest request = new MockHttpServletRequest(sc);
ServletWebRequest webRequest = new ServletWebRequest(request);
replay(manager, factory);
interceptor.preHandle(webRequest);
assertTrue(TransactionSynchronizationManager.hasResource(factory));
verify(manager, factory);
AsyncWebRequest asyncWebRequest = createStrictMock(AsyncWebRequest.class);
asyncWebRequest.addCompletionHandler((Runnable) anyObject());
asyncWebRequest.startAsync();
replay(asyncWebRequest);
WebAsyncManager asyncManager = AsyncWebUtils.getAsyncManager(webRequest);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.startCallableProcessing(new Callable<String>() {
public String call() throws Exception {
return "anything";
}
});
verify(asyncWebRequest);
reset(asyncWebRequest);
replay(asyncWebRequest);
interceptor.afterConcurrentHandlingStarted(webRequest);
assertFalse(TransactionSynchronizationManager.hasResource(factory));
// Async dispatch thread
reset(manager, factory);
replay(manager, factory);
interceptor.preHandle(webRequest);
assertTrue(TransactionSynchronizationManager.hasResource(factory));
verify(manager, factory);
reset(manager, factory);
replay(manager, factory);
asyncManager.clearConcurrentResult();
// check that further invocations simply participate
interceptor.preHandle(new ServletWebRequest(request));
interceptor.preHandle(new ServletWebRequest(request));
interceptor.postHandle(new ServletWebRequest(request), null);
interceptor.afterCompletion(new ServletWebRequest(request), null);
interceptor.postHandle(new ServletWebRequest(request), null);
interceptor.afterCompletion(new ServletWebRequest(request), null);
interceptor.preHandle(new ServletWebRequest(request));
interceptor.postHandle(new ServletWebRequest(request), null);
interceptor.afterCompletion(new ServletWebRequest(request), null);
verify(manager, factory);
reset(manager, factory);
replay(manager, factory);
interceptor.postHandle(webRequest, null);
assertTrue(TransactionSynchronizationManager.hasResource(factory));
verify(manager, factory);
reset(manager, factory);
expect(manager.isOpen()).andReturn(true);
manager.close();
replay(manager, factory);
interceptor.afterCompletion(webRequest, null);
assertFalse(TransactionSynchronizationManager.hasResource(factory));
verify(manager, factory);
}
public void testOpenEntityManagerInViewFilter() throws Exception {
managerControl.expectAndReturn(manager.isOpen(), true);
expect(manager.isOpen()).andReturn(true);
manager.close();
managerControl.replay();
factoryControl.replay();
replay(manager, factory);
MockControl factoryControl2 = MockControl.createControl(EntityManagerFactory.class);
final EntityManagerFactory factory2 = (EntityManagerFactory) factoryControl2.getMock();
final EntityManagerFactory factory2 = (EntityManagerFactory) createMock(EntityManagerFactory.class);
final EntityManager manager2 = (EntityManager) createMock(EntityManager.class);
MockControl managerControl2 = MockControl.createControl(EntityManager.class);
EntityManager manager2 = (EntityManager) managerControl2.getMock();
factoryControl2.expectAndReturn(factory2.createEntityManager(), manager2);
managerControl2.expectAndReturn(manager2.isOpen(), true);
expect(factory2.createEntityManager()).andReturn(manager2);
expect(manager2.isOpen()).andReturn(true);
manager2.close();
factoryControl2.replay();
managerControl2.replay();
replay(factory2, manager2);
MockServletContext sc = new MockServletContext();
StaticWebApplicationContext wac = new StaticWebApplicationContext();
@@ -195,10 +282,109 @@ public class OpenEntityManagerInViewTests extends TestCase {
assertFalse(TransactionSynchronizationManager.hasResource(factory2));
assertNotNull(request.getAttribute("invoked"));
factoryControl.verify();
managerControl.verify();
factoryControl2.verify();
managerControl2.verify();
verify(manager, factory);
verify(factory2, manager2);
wac.close();
}
public void testOpenEntityManagerInViewFilterAsyncScenario() throws Exception {
expect(manager.isOpen()).andReturn(true);
manager.close();
replay(manager, factory);
final EntityManagerFactory factory2 = (EntityManagerFactory) createMock(EntityManagerFactory.class);
final EntityManager manager2 = (EntityManager) createMock(EntityManager.class);
expect(factory2.createEntityManager()).andReturn(manager2);
expect(manager2.isOpen()).andReturn(true);
manager2.close();
replay(factory2, manager2);
MockServletContext sc = new MockServletContext();
StaticWebApplicationContext wac = new StaticWebApplicationContext();
wac.setServletContext(sc);
wac.getDefaultListableBeanFactory().registerSingleton("entityManagerFactory", factory);
wac.getDefaultListableBeanFactory().registerSingleton("myEntityManagerFactory", factory2);
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");
filterConfig2.addInitParameter("entityManagerFactoryBeanName", "myEntityManagerFactory");
final OpenEntityManagerInViewFilter filter = new OpenEntityManagerInViewFilter();
filter.init(filterConfig);
final OpenEntityManagerInViewFilter filter2 = new OpenEntityManagerInViewFilter();
filter2.init(filterConfig2);
final AtomicInteger count = new AtomicInteger(0);
final FilterChain filterChain = new FilterChain() {
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) {
assertTrue(TransactionSynchronizationManager.hasResource(factory));
servletRequest.setAttribute("invoked", Boolean.TRUE);
count.incrementAndGet();
}
};
final AtomicInteger count2 = new AtomicInteger(0);
final FilterChain filterChain2 = new FilterChain() {
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse)
throws IOException, ServletException {
assertTrue(TransactionSynchronizationManager.hasResource(factory2));
filter.doFilter(servletRequest, servletResponse, filterChain);
count2.incrementAndGet();
}
};
FilterChain filterChain3 = new PassThroughFilterChain(filter2, filterChain2);
AsyncWebRequest asyncWebRequest = createStrictMock(AsyncWebRequest.class);
asyncWebRequest.addCompletionHandler((Runnable) anyObject());
asyncWebRequest.startAsync();
expect(asyncWebRequest.isAsyncStarted()).andReturn(true);
expectLastCall().anyTimes();
replay(asyncWebRequest);
WebAsyncManager asyncManager = AsyncWebUtils.getAsyncManager(request);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.startCallableProcessing(new Callable<String>() {
public String call() throws Exception {
return "anything";
}
});
assertFalse(TransactionSynchronizationManager.hasResource(factory));
assertFalse(TransactionSynchronizationManager.hasResource(factory2));
filter2.doFilter(request, response, filterChain3);
assertFalse(TransactionSynchronizationManager.hasResource(factory));
assertFalse(TransactionSynchronizationManager.hasResource(factory2));
assertEquals(1, count.get());
assertEquals(1, count2.get());
assertNotNull(request.getAttribute("invoked"));
// Async dispatch after concurrent handling produces result ...
reset(asyncWebRequest);
expect(asyncWebRequest.isAsyncStarted()).andReturn(false).anyTimes();
replay(asyncWebRequest);
assertFalse(TransactionSynchronizationManager.hasResource(factory));
assertFalse(TransactionSynchronizationManager.hasResource(factory2));
filter.doFilter(request, response, filterChain3);
assertFalse(TransactionSynchronizationManager.hasResource(factory));
assertFalse(TransactionSynchronizationManager.hasResource(factory2));
assertEquals(2, count.get());
assertEquals(2, count2.get());
verify(manager, factory);
verify(factory2, manager2);
wac.close();
}