diff --git a/build.gradle b/build.gradle
index 2ea0800567e..d72b3f0360a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -366,9 +366,13 @@ project('spring-web') {
compile("org.codehaus.jackson:jackson-mapper-asl:1.4.2", optional)
compile("com.fasterxml.jackson.core:jackson-databind:2.0.1", optional)
compile("taglibs:standard:1.1.2", optional)
- compile("org.mortbay.jetty:jetty:6.1.9") { dep ->
+ compile("org.eclipse.jetty:jetty-servlet:8.1.5.v20120716") { dep ->
optional dep
- exclude group: 'org.mortbay.jetty', module: 'servlet-api-2.5'
+ exclude group: 'org.eclipse.jetty.orbit', module: 'javax.servlet'
+ }
+ compile("org.eclipse.jetty:jetty-server:8.1.5.v20120716") { dep ->
+ optional dep
+ exclude group: 'org.eclipse.jetty.orbit', module: 'javax.servlet'
}
testCompile project(":spring-context-support") // for JafMediaTypeFactory
testCompile "xmlunit:xmlunit:1.2"
diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.java b/spring-orm/src/main/java/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.java
index f55ae4e4366..1af4dc4d2f9 100644
--- a/spring-orm/src/main/java/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.java
+++ b/spring-orm/src/main/java/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.java
@@ -17,6 +17,7 @@
package org.springframework.orm.hibernate3.support;
import java.io.IOException;
+
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@@ -25,14 +26,15 @@ import javax.servlet.http.HttpServletResponse;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
-
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.orm.hibernate3.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.util.Assert;
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.request.async.AsyncWebUtils;
+import org.springframework.web.context.request.async.WebAsyncManager;
+import org.springframework.web.context.request.async.WebAsyncManager.AsyncThreadInitializer;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.OncePerRequestFilter;
@@ -165,16 +167,27 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
}
+ /**
+ * The default value is "true" so that the filter may re-bind the opened
+ * {@code Session} 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(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
- AsyncExecutionChain chain = AsyncExecutionChain.getForCurrentRequest(request);
-
SessionFactory sessionFactory = lookupSessionFactory(request);
boolean participate = false;
+ WebAsyncManager asyncManager = AsyncWebUtils.getAsyncManager(request);
+ String key = getAlreadyFilteredAttributeName();
+
if (isSingleSession()) {
// single session mode
if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
@@ -182,16 +195,20 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
participate = true;
}
else {
- logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");
- Session session = getSession(sessionFactory);
- SessionHolder sessionHolder = new SessionHolder(session);
- TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
+ if (!isAsyncDispatch(request) || !asyncManager.applyAsyncThreadInitializer(key)) {
+ logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");
+ Session session = getSession(sessionFactory);
+ SessionHolder sessionHolder = new SessionHolder(session);
+ TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
- chain.push(getAsyncCallable(request, sessionFactory, sessionHolder));
+ AsyncThreadInitializer initializer = createAsyncThreadInitializer(sessionFactory, sessionHolder);
+ asyncManager.registerAsyncThreadInitializer(key, initializer);
+ }
}
}
else {
// deferred close mode
+ Assert.state(isLastRequestThread(request), "Deferred close mode is not supported on async dispatches");
if (SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) {
// Do not modify deferred close: just set the participate flag.
participate = true;
@@ -210,16 +227,12 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
// single session mode
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
- if (!chain.pop()) {
- return;
+ if (isLastRequestThread(request)) {
+ logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");
+ closeSession(sessionHolder.getSession(), sessionFactory);
}
- logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");
- closeSession(sessionHolder.getSession(), sessionFactory);
}
else {
- if (chain.isAsyncStarted()) {
- throw new IllegalStateException("Deferred close is not supported with async requests.");
- }
// deferred close mode
SessionFactoryUtils.processDeferredClose(sessionFactory);
}
@@ -227,6 +240,19 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
}
}
+ private AsyncThreadInitializer createAsyncThreadInitializer(final SessionFactory sessionFactory,
+ final SessionHolder sessionHolder) {
+
+ return new AsyncThreadInitializer() {
+ 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.
@@ -291,28 +317,4 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
SessionFactoryUtils.closeSession(session);
}
- /**
- * Create a Callable to extend the use of the open Hibernate Session to the
- * async thread completing the request.
- */
- private AbstractDelegatingCallable getAsyncCallable(final HttpServletRequest request,
- final SessionFactory sessionFactory, final SessionHolder sessionHolder) {
-
- return new AbstractDelegatingCallable() {
- public Object call() throws Exception {
- TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
- try {
- getNext().call();
- }
- finally {
- SessionHolder sessionHolder =
- (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
- logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
- SessionFactoryUtils.closeSession(sessionHolder.getSession());
- }
- return null;
- }
- };
- }
-
}
diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate3/support/OpenSessionInViewInterceptor.java b/spring-orm/src/main/java/org/springframework/orm/hibernate3/support/OpenSessionInViewInterceptor.java
index 253442389e3..5f7ca275490 100644
--- a/spring-orm/src/main/java/org/springframework/orm/hibernate3/support/OpenSessionInViewInterceptor.java
+++ b/spring-orm/src/main/java/org/springframework/orm/hibernate3/support/OpenSessionInViewInterceptor.java
@@ -25,8 +25,10 @@ import org.springframework.orm.hibernate3.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.WebRequest;
-import org.springframework.web.context.request.async.AbstractDelegatingCallable;
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.AsyncThreadInitializer;
/**
* Spring web request interceptor that binds a Hibernate Session to the
@@ -140,10 +142,19 @@ public class OpenSessionInViewInterceptor extends HibernateAccessor implements A
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession
*/
public void preHandle(WebRequest request) throws DataAccessException {
+
+ WebAsyncManager asyncManager = AsyncWebUtils.getAsyncManager(request);
+ String participateAttributeName = getParticipateAttributeName();
+
+ if (asyncManager.hasConcurrentResult()) {
+ if (asyncManager.applyAsyncThreadInitializer(participateAttributeName)) {
+ return;
+ }
+ }
+
if ((isSingleSession() && TransactionSynchronizationManager.hasResource(getSessionFactory())) ||
SessionFactoryUtils.isDeferredCloseActive(getSessionFactory())) {
// Do not modify the Session: 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);
@@ -157,6 +168,9 @@ public class OpenSessionInViewInterceptor extends HibernateAccessor implements A
applyFlushMode(session, false);
SessionHolder sessionHolder = new SessionHolder(session);
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
+
+ AsyncThreadInitializer asyncThreadInitializer = createThreadInitializer(sessionHolder);
+ asyncManager.registerAsyncThreadInitializer(participateAttributeName, asyncThreadInitializer);
}
else {
// deferred close mode
@@ -165,44 +179,6 @@ public class OpenSessionInViewInterceptor extends HibernateAccessor implements A
}
}
- /**
- * Create a Callable to bind the Hibernate 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);
- getNext().call();
- return null;
- }
- };
- }
-
- /**
- * Unbind the Hibernate Session from the main thread but leave
- * the Session open for further use from the async thread.
- */
- public void postHandleAsyncStarted(WebRequest request) {
- String attributeName = getParticipateAttributeName();
- if (request.getAttribute(attributeName, WebRequest.SCOPE_REQUEST) == null) {
- if (isSingleSession()) {
- TransactionSynchronizationManager.unbindResource(getSessionFactory());
- }
- else {
- throw new IllegalStateException("Deferred close is not supported with async requests.");
- }
- }
- }
-
/**
* Flush the Hibernate Session before view rendering, if necessary.
*
Note that this just applies in {@link #isSingleSession() single session mode}!
@@ -232,18 +208,7 @@ public class OpenSessionInViewInterceptor extends HibernateAccessor implements A
* @see org.springframework.transaction.support.TransactionSynchronizationManager
*/
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 Session: 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)) {
if (isSingleSession()) {
// single session mode
SessionHolder sessionHolder =
@@ -258,6 +223,34 @@ public class OpenSessionInViewInterceptor extends HibernateAccessor implements A
}
}
+ public void afterConcurrentHandlingStarted(WebRequest request) {
+ if (!decrementParticipateCount(request)) {
+ if (isSingleSession()) {
+ TransactionSynchronizationManager.unbindResource(getSessionFactory());
+ }
+ else {
+ throw new IllegalStateException("Deferred close mode is not supported with async requests.");
+ }
+
+ }
+ }
+
+ 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;
+ }
+
/**
* Return the name of the request attribute that identifies that a request is
* already intercepted.
@@ -268,4 +261,15 @@ public class OpenSessionInViewInterceptor extends HibernateAccessor implements A
return getSessionFactory().toString() + PARTICIPATE_SUFFIX;
}
+ private AsyncThreadInitializer createThreadInitializer(final SessionHolder sessionHolder) {
+ return new AsyncThreadInitializer() {
+ public void initialize() {
+ TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
+ }
+ public void reset() {
+ TransactionSynchronizationManager.unbindResource(getSessionFactory());
+ }
+ };
+ }
+
}
diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate4/support/OpenSessionInViewFilter.java b/spring-orm/src/main/java/org/springframework/orm/hibernate4/support/OpenSessionInViewFilter.java
index 9f1f0b10dea..329a4e4eca1 100644
--- a/spring-orm/src/main/java/org/springframework/orm/hibernate4/support/OpenSessionInViewFilter.java
+++ b/spring-orm/src/main/java/org/springframework/orm/hibernate4/support/OpenSessionInViewFilter.java
@@ -17,6 +17,7 @@
package org.springframework.orm.hibernate4.support;
import java.io.IOException;
+
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@@ -26,14 +27,14 @@ import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
-
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.orm.hibernate4.SessionFactoryUtils;
import org.springframework.orm.hibernate4.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.context.WebApplicationContext;
-import org.springframework.web.context.request.async.AbstractDelegatingCallable;
-import org.springframework.web.context.request.async.AsyncExecutionChain;
+import org.springframework.web.context.request.async.AsyncWebUtils;
+import org.springframework.web.context.request.async.WebAsyncManager;
+import org.springframework.web.context.request.async.WebAsyncManager.AsyncThreadInitializer;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.OncePerRequestFilter;
@@ -99,27 +100,41 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
}
+ /**
+ * The default value is "true" so that the filter may re-bind the opened
+ * {@code Session} 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(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
- AsyncExecutionChain chain = AsyncExecutionChain.getForCurrentRequest(request);
-
SessionFactory sessionFactory = lookupSessionFactory(request);
boolean participate = false;
+ WebAsyncManager asyncManager = AsyncWebUtils.getAsyncManager(request);
+ String key = getAlreadyFilteredAttributeName();
+
if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
// Do not modify the Session: just set the participate flag.
participate = true;
}
else {
- logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");
- Session session = openSession(sessionFactory);
- SessionHolder sessionHolder = new SessionHolder(session);
- TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
+ if (!isAsyncDispatch(request) || !asyncManager.applyAsyncThreadInitializer(key)) {
+ logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");
+ Session session = openSession(sessionFactory);
+ SessionHolder sessionHolder = new SessionHolder(session);
+ TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
- chain.push(getAsyncCallable(request, sessionFactory, sessionHolder));
+ AsyncThreadInitializer initializer = createAsyncThreadInitializer(sessionFactory, sessionHolder);
+ asyncManager.registerAsyncThreadInitializer(key, initializer);
+ }
}
try {
@@ -130,15 +145,27 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
if (!participate) {
SessionHolder sessionHolder =
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
- if (!chain.pop()) {
- return;
+ if (isLastRequestThread(request)) {
+ logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
+ SessionFactoryUtils.closeSession(sessionHolder.getSession());
}
- logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
- SessionFactoryUtils.closeSession(sessionHolder.getSession());
}
}
}
+ private AsyncThreadInitializer createAsyncThreadInitializer(final SessionFactory sessionFactory,
+ final SessionHolder sessionHolder) {
+
+ return new AsyncThreadInitializer() {
+ 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.
@@ -187,28 +214,4 @@ 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 {
- getNext().call();
- }
- finally {
- SessionHolder sessionHolder =
- (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
- logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
- SessionFactoryUtils.closeSession(sessionHolder.getSession());
- }
- return null;
- }
- };
- }
-
}
diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate4/support/OpenSessionInViewInterceptor.java b/spring-orm/src/main/java/org/springframework/orm/hibernate4/support/OpenSessionInViewInterceptor.java
index 7bd43ac9394..6132430c38a 100644
--- a/spring-orm/src/main/java/org/springframework/orm/hibernate4/support/OpenSessionInViewInterceptor.java
+++ b/spring-orm/src/main/java/org/springframework/orm/hibernate4/support/OpenSessionInViewInterceptor.java
@@ -29,9 +29,10 @@ import org.springframework.orm.hibernate4.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.WebRequest;
-import org.springframework.web.context.request.async.AbstractDelegatingCallable;
-import org.springframework.web.context.request.async.AsyncExecutionChain;
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.AsyncThreadInitializer;
/**
* Spring web request interceptor that binds a Hibernate Session to the
@@ -103,9 +104,18 @@ public class OpenSessionInViewInterceptor implements AsyncWebRequestInterceptor
* {@link org.springframework.transaction.support.TransactionSynchronizationManager}.
*/
public void preHandle(WebRequest request) throws DataAccessException {
+
+ WebAsyncManager asyncManager = AsyncWebUtils.getAsyncManager(request);
+ String participateAttributeName = getParticipateAttributeName();
+
+ if (asyncManager.hasConcurrentResult()) {
+ if (asyncManager.applyAsyncThreadInitializer(participateAttributeName)) {
+ return;
+ }
+ }
+
if (TransactionSynchronizationManager.hasResource(getSessionFactory())) {
// Do not modify the Session: 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);
@@ -115,6 +125,9 @@ public class OpenSessionInViewInterceptor implements AsyncWebRequestInterceptor
Session session = openSession();
SessionHolder sessionHolder = new SessionHolder(session);
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
+
+ AsyncThreadInitializer asyncThreadInitializer = createThreadInitializer(sessionHolder);
+ asyncManager.registerAsyncThreadInitializer(participateAttributeName, asyncThreadInitializer);
}
}
@@ -122,60 +135,39 @@ public class OpenSessionInViewInterceptor implements AsyncWebRequestInterceptor
}
/**
- * Create a Callable to bind the Hibernate session
- * to the async request thread.
+ * Unbind the Hibernate Session from the thread and close it).
+ * @see org.springframework.transaction.support.TransactionSynchronizationManager
*/
- 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());
+ public void afterCompletion(WebRequest request, Exception ex) throws DataAccessException {
+ if (!decrementParticipateCount(request)) {
+ SessionHolder sessionHolder =
+ (SessionHolder) TransactionSynchronizationManager.unbindResource(getSessionFactory());
+ logger.debug("Closing Hibernate Session in OpenSessionInViewInterceptor");
+ SessionFactoryUtils.closeSession(sessionHolder.getSession());
- return new AbstractDelegatingCallable() {
- public Object call() throws Exception {
- TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
- getNext().call();
- return null;
- }
- };
+ }
}
- /**
- * Unbind the Hibernate Session 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) {
+ public void afterConcurrentHandlingStarted(WebRequest request) {
+ if (!decrementParticipateCount(request)) {
TransactionSynchronizationManager.unbindResource(getSessionFactory());
}
}
- /**
- * Unbind the Hibernate Session from the thread and close it).
- * @see org.springframework.transaction.support.TransactionSynchronizationManager
- */
- public void afterCompletion(WebRequest request, Exception ex) throws DataAccessException {
+ private boolean decrementParticipateCount(WebRequest request) {
String participateAttributeName = getParticipateAttributeName();
Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
- if (count != null) {
- // 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);
- }
+ 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 {
- SessionHolder sessionHolder =
- (SessionHolder) TransactionSynchronizationManager.unbindResource(getSessionFactory());
- logger.debug("Closing Hibernate Session in OpenSessionInViewInterceptor");
- SessionFactoryUtils.closeSession(sessionHolder.getSession());
+ request.removeAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
}
+ return true;
}
/**
@@ -208,4 +200,15 @@ public class OpenSessionInViewInterceptor implements AsyncWebRequestInterceptor
return getSessionFactory().toString() + PARTICIPATE_SUFFIX;
}
+ private AsyncThreadInitializer createThreadInitializer(final SessionHolder sessionHolder) {
+ return new AsyncThreadInitializer() {
+ public void initialize() {
+ TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
+ }
+ public void reset() {
+ TransactionSynchronizationManager.unbindResource(getSessionFactory());
+ }
+ };
+ }
+
}
diff --git a/spring-orm/src/test/java/org/springframework/orm/hibernate3/support/OpenSessionInViewTests.java b/spring-orm/src/test/java/org/springframework/orm/hibernate3/support/OpenSessionInViewTests.java
index b31747558d2..9a845214d5f 100644
--- a/spring-orm/src/test/java/org/springframework/orm/hibernate3/support/OpenSessionInViewTests.java
+++ b/spring-orm/src/test/java/org/springframework/orm/hibernate3/support/OpenSessionInViewTests.java
@@ -16,8 +16,10 @@
package org.springframework.orm.hibernate3.support;
+import static org.easymock.EasyMock.anyObject;
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;
@@ -29,6 +31,7 @@ import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.sql.Connection;
import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicInteger;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
@@ -59,9 +62,9 @@ import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.ServletWebRequest;
-import org.springframework.web.context.request.async.AbstractDelegatingCallable;
-import org.springframework.web.context.request.async.AsyncExecutionChain;
import org.springframework.web.context.request.async.AsyncWebRequest;
+import org.springframework.web.context.request.async.AsyncWebUtils;
+import org.springframework.web.context.request.async.WebAsyncManager;
import org.springframework.web.context.support.StaticWebApplicationContext;
@@ -152,6 +155,8 @@ public class OpenSessionInViewTests {
@Test
public void testOpenSessionInViewInterceptorAsyncScenario() throws Exception {
+ // Initial request thread
+
final SessionFactory sf = createStrictMock(SessionFactory.class);
Session session = createStrictMock(Session.class);
@@ -167,39 +172,52 @@ public class OpenSessionInViewTests {
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.setNext(new Callable