Add timeout async request handling to OSIV components

This change adds async web request timeout handling to OSIV filters
and interceptors to ensure the session or entity manager is released.

Issue: SPR-10874
This commit is contained in:
Rossen Stoyanchev 2013-10-30 22:50:01 -04:00
parent 1ac8e48ebf
commit f9081bedb4
10 changed files with 371 additions and 213 deletions

View File

@ -0,0 +1,109 @@
/*
* Copyright 2002-2013 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.orm.hibernate4.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate4.SessionFactoryUtils;
import org.springframework.orm.hibernate4.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.async.CallableProcessingInterceptorAdapter;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.context.request.async.DeferredResultProcessingInterceptor;
import java.util.concurrent.Callable;
/**
* An interceptor with asynchronous web requests used in OpenSessionInViewFilter and
* OpenSessionInViewInterceptor.
*
* Ensures the following:
* 1) The session is bound/unbound when "callable processing" is started
* 2) The session is closed if an async request times out
*
* @author Rossen Stoyanchev
* @since 3.2.5
*/
public class AsyncRequestInterceptor extends CallableProcessingInterceptorAdapter
implements DeferredResultProcessingInterceptor {
private static Log logger = LogFactory.getLog(AsyncRequestInterceptor.class);
private final SessionFactory sessionFactory;
private final SessionHolder sessionHolder;
private volatile boolean timeoutInProgress;
public AsyncRequestInterceptor(SessionFactory sessionFactory, SessionHolder sessionHolder) {
this.sessionFactory = sessionFactory;
this.sessionHolder = sessionHolder;
}
@Override
public <T> void preProcess(NativeWebRequest request, Callable<T> task) {
bindSession();
}
public void bindSession() {
this.timeoutInProgress = false;
TransactionSynchronizationManager.bindResource(this.sessionFactory, this.sessionHolder);
}
@Override
public <T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) {
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
}
@Override
public <T> Object handleTimeout(NativeWebRequest request, Callable<T> task) {
this.timeoutInProgress = true;
return RESULT_NONE; // give other interceptors a chance to handle the timeout
}
@Override
public <T> void afterCompletion(NativeWebRequest request, Callable<T> task) throws Exception {
closeAfterTimeout();
}
private void closeAfterTimeout() {
if (this.timeoutInProgress) {
logger.debug("Closing Hibernate Session after async request timeout");
SessionFactoryUtils.closeSession(sessionHolder.getSession());
}
}
// Implementation of DeferredResultProcessingInterceptor methods
public <T> void beforeConcurrentHandling(NativeWebRequest request, DeferredResult<T> deferredResult) { }
public <T> void preProcess(NativeWebRequest request, DeferredResult<T> deferredResult) { }
public <T> void postProcess(NativeWebRequest request, DeferredResult<T> deferredResult, Object result) { }
@Override
public <T> boolean handleTimeout(NativeWebRequest request, DeferredResult<T> deferredResult) {
this.timeoutInProgress = true;
return true; // give other interceptors a chance to handle the timeout
}
@Override
public <T> void afterCompletion(NativeWebRequest request, DeferredResult<T> deferredResult) {
closeAfterTimeout();
}
}

View File

@ -16,14 +16,6 @@
package org.springframework.orm.hibernate4.support;
import java.io.IOException;
import java.util.concurrent.Callable;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Session;
@ -33,13 +25,17 @@ 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.NativeWebRequest;
import org.springframework.web.context.request.async.CallableProcessingInterceptorAdapter;
import org.springframework.web.context.request.async.WebAsyncManager;
import org.springframework.web.context.request.async.WebAsyncUtils;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Servlet 2.3 Filter that binds a Hibernate Session to the thread for the entire
* processing of the request. Intended for the "Open Session in View" pattern,
@ -143,8 +139,9 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
SessionHolder sessionHolder = new SessionHolder(session);
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
asyncManager.registerCallableInterceptor(key,
new SessionBindingCallableInterceptor(sessionFactory, sessionHolder));
AsyncRequestInterceptor interceptor = new AsyncRequestInterceptor(sessionFactory, sessionHolder);
asyncManager.registerCallableInterceptor(key, interceptor);
asyncManager.registerDeferredResultInterceptor(key, interceptor);
}
}
@ -216,37 +213,8 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
if (asyncManager.getCallableInterceptor(key) == null) {
return false;
}
((SessionBindingCallableInterceptor) asyncManager.getCallableInterceptor(key)).initializeThread();
((AsyncRequestInterceptor) asyncManager.getCallableInterceptor(key)).bindSession();
return true;
}
/**
* Bind and unbind the Hibernate {@code Session} to the current thread.
*/
private static class SessionBindingCallableInterceptor extends CallableProcessingInterceptorAdapter {
private final SessionFactory sessionFactory;
private final SessionHolder sessionHolder;
public SessionBindingCallableInterceptor(SessionFactory sessionFactory, SessionHolder sessionHolder) {
this.sessionFactory = sessionFactory;
this.sessionHolder = sessionHolder;
}
@Override
public <T> void preProcess(NativeWebRequest request, Callable<T> task) {
initializeThread();
}
@Override
public <T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) {
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
}
private void initializeThread() {
TransactionSynchronizationManager.bindResource(this.sessionFactory, this.sessionHolder);
}
}
}

View File

@ -33,9 +33,7 @@ import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.AsyncWebRequestInterceptor;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.async.CallableProcessingInterceptorAdapter;
import org.springframework.web.context.request.async.WebAsyncManager;
import org.springframework.web.context.request.async.WebAsyncUtils;
import org.springframework.web.context.request.async.*;
/**
* Spring web request interceptor that binds a Hibernate {@code Session} to the
@ -118,8 +116,10 @@ public class OpenSessionInViewInterceptor implements AsyncWebRequestInterceptor
SessionHolder sessionHolder = new SessionHolder(session);
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
asyncManager.registerCallableInterceptor(participateAttributeName,
new SessionBindingCallableInterceptor(sessionHolder));
AsyncRequestInterceptor asyncRequestInterceptor =
new AsyncRequestInterceptor(getSessionFactory(), sessionHolder);
asyncManager.registerCallableInterceptor(participateAttributeName, asyncRequestInterceptor);
asyncManager.registerDeferredResultInterceptor(participateAttributeName, asyncRequestInterceptor);
}
}
@ -196,35 +196,8 @@ public class OpenSessionInViewInterceptor implements AsyncWebRequestInterceptor
if (asyncManager.getCallableInterceptor(key) == null) {
return false;
}
((SessionBindingCallableInterceptor) asyncManager.getCallableInterceptor(key)).initializeThread();
((AsyncRequestInterceptor) asyncManager.getCallableInterceptor(key)).bindSession();
return true;
}
/**
* Bind and unbind the Hibernate {@code Session} to the current thread.
*/
private class SessionBindingCallableInterceptor extends CallableProcessingInterceptorAdapter {
private final SessionHolder sessionHolder;
public SessionBindingCallableInterceptor(SessionHolder sessionHolder) {
this.sessionHolder = sessionHolder;
}
@Override
public <T> void preProcess(NativeWebRequest request, Callable<T> task) {
initializeThread();
}
@Override
public <T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) {
TransactionSynchronizationManager.unbindResource(getSessionFactory());
}
private void initializeThread() {
TransactionSynchronizationManager.bindResource(getSessionFactory(), this.sessionHolder);
}
}
}

View File

@ -0,0 +1,110 @@
/*
* Copyright 2002-2013 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.orm.hibernate3.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.orm.hibernate3.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.async.CallableProcessingInterceptorAdapter;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.context.request.async.DeferredResultProcessingInterceptor;
import java.util.concurrent.Callable;
/**
* An interceptor with asynchronous web requests used in OpenSessionInViewFilter and
* OpenSessionInViewInterceptor.
*
* Ensures the following:
* 1) The session is bound/unbound when "callable processing" is started
* 2) The session is closed if an async request times out
*
* @author Rossen Stoyanchev
* @since 3.2.5
*/
class AsyncRequestInterceptor extends CallableProcessingInterceptorAdapter
implements DeferredResultProcessingInterceptor {
private static final Log logger = LogFactory.getLog(AsyncRequestInterceptor.class);
private final SessionFactory sessionFactory;
private final SessionHolder sessionHolder;
private volatile boolean timeoutInProgress;
public AsyncRequestInterceptor(SessionFactory sessionFactory, SessionHolder sessionHolder) {
this.sessionFactory = sessionFactory;
this.sessionHolder = sessionHolder;
}
@Override
public <T> void preProcess(NativeWebRequest request, Callable<T> task) {
bindSession();
}
public void bindSession() {
this.timeoutInProgress = false;
TransactionSynchronizationManager.bindResource(this.sessionFactory, this.sessionHolder);
}
@Override
public <T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) {
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
}
@Override
public <T> Object handleTimeout(NativeWebRequest request, Callable<T> task) {
this.timeoutInProgress = true;
return RESULT_NONE; // give other interceptors a chance to handle the timeout
}
@Override
public <T> void afterCompletion(NativeWebRequest request, Callable<T> task) throws Exception {
closeAfterTimeout();
}
private void closeAfterTimeout() {
if (this.timeoutInProgress) {
logger.debug("Closing Hibernate Session after async request timeout");
SessionFactoryUtils.closeSession(sessionHolder.getSession());
}
}
// Implementation of DeferredResultProcessingInterceptor methods
public <T> void beforeConcurrentHandling(NativeWebRequest request, DeferredResult<T> deferredResult) {}
public <T> void preProcess(NativeWebRequest request, DeferredResult<T> deferredResult) {}
public <T> void postProcess(NativeWebRequest request, DeferredResult<T> deferredResult, Object result) {}
@Override
public <T> boolean handleTimeout(NativeWebRequest request, DeferredResult<T> deferredResult) {
this.timeoutInProgress = true;
return true; // give other interceptors a chance to handle the timeout
}
@Override
public <T> void afterCompletion(NativeWebRequest request, DeferredResult<T> deferredResult) {
closeAfterTimeout();
}
}

View File

@ -17,7 +17,6 @@
package org.springframework.orm.hibernate3.support;
import java.io.IOException;
import java.util.concurrent.Callable;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
@ -33,10 +32,7 @@ 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.NativeWebRequest;
import org.springframework.web.context.request.async.CallableProcessingInterceptorAdapter;
import org.springframework.web.context.request.async.WebAsyncManager;
import org.springframework.web.context.request.async.WebAsyncUtils;
import org.springframework.web.context.request.async.*;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.OncePerRequestFilter;
@ -212,8 +208,9 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
SessionHolder sessionHolder = new SessionHolder(session);
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
asyncManager.registerCallableInterceptor(key,
new SessionBindingCallableInterceptor(sessionFactory, sessionHolder));
AsyncRequestInterceptor interceptor = new AsyncRequestInterceptor(sessionFactory, sessionHolder);
asyncManager.registerCallableInterceptor(key, interceptor);
asyncManager.registerDeferredResultInterceptor(key, interceptor);
}
}
}
@ -319,38 +316,8 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
if (asyncManager.getCallableInterceptor(key) == null) {
return false;
}
((SessionBindingCallableInterceptor) asyncManager.getCallableInterceptor(key)).initializeThread();
((AsyncRequestInterceptor) asyncManager.getCallableInterceptor(key)).bindSession();
return true;
}
/**
* Bind and unbind the Hibernate {@code Session} to the current thread.
*/
private static class SessionBindingCallableInterceptor extends CallableProcessingInterceptorAdapter {
private final SessionFactory sessionFactory;
private final SessionHolder sessionHolder;
public SessionBindingCallableInterceptor(SessionFactory sessionFactory, SessionHolder sessionHolder) {
this.sessionFactory = sessionFactory;
this.sessionHolder = sessionHolder;
}
@Override
public <T> void preProcess(NativeWebRequest request, Callable<T> task) {
initializeThread();
}
@Override
public <T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) {
TransactionSynchronizationManager.unbindResource(this.sessionFactory);
}
private void initializeThread() {
TransactionSynchronizationManager.bindResource(this.sessionFactory, this.sessionHolder);
}
}
}

View File

@ -29,9 +29,7 @@ import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.AsyncWebRequestInterceptor;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.async.CallableProcessingInterceptorAdapter;
import org.springframework.web.context.request.async.WebAsyncManager;
import org.springframework.web.context.request.async.WebAsyncUtils;
import org.springframework.web.context.request.async.*;
/**
* Spring web request interceptor that binds a Hibernate {@code Session} to the
@ -172,8 +170,10 @@ public class OpenSessionInViewInterceptor extends HibernateAccessor implements A
SessionHolder sessionHolder = new SessionHolder(session);
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
asyncManager.registerCallableInterceptor(participateAttributeName,
new SessionBindingCallableInterceptor(sessionHolder));
AsyncRequestInterceptor asyncRequestInterceptor =
new AsyncRequestInterceptor(getSessionFactory(), sessionHolder);
asyncManager.registerCallableInterceptor(participateAttributeName, asyncRequestInterceptor);
asyncManager.registerDeferredResultInterceptor(participateAttributeName, asyncRequestInterceptor);
}
else {
// deferred close mode
@ -268,34 +268,8 @@ public class OpenSessionInViewInterceptor extends HibernateAccessor implements A
if (asyncManager.getCallableInterceptor(key) == null) {
return false;
}
((SessionBindingCallableInterceptor) asyncManager.getCallableInterceptor(key)).initializeThread();
((AsyncRequestInterceptor) asyncManager.getCallableInterceptor(key)).bindSession();
return true;
}
/**
* Bind and unbind the Hibernate {@code Session} to the current thread.
*/
private class SessionBindingCallableInterceptor extends CallableProcessingInterceptorAdapter {
private final SessionHolder sessionHolder;
public SessionBindingCallableInterceptor(SessionHolder sessionHolder) {
this.sessionHolder = sessionHolder;
}
@Override
public <T> void preProcess(NativeWebRequest request, Callable<T> task) {
initializeThread();
}
@Override
public <T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) {
TransactionSynchronizationManager.unbindResource(getSessionFactory());
}
private void initializeThread() {
TransactionSynchronizationManager.bindResource(getSessionFactory(), this.sessionHolder);
}
}
}

View File

@ -0,0 +1,111 @@
/*
* Copyright 2002-2013 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.orm.jpa.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.orm.jpa.EntityManagerFactoryUtils;
import org.springframework.orm.jpa.EntityManagerHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.async.CallableProcessingInterceptorAdapter;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.context.request.async.DeferredResultProcessingInterceptor;
import javax.persistence.EntityManagerFactory;
import java.util.concurrent.Callable;
/**
* An interceptor with asynchronous web requests used in OpenSessionInViewFilter and
* OpenSessionInViewInterceptor.
*
* Ensures the following:
* 1) The session is bound/unbound when "callable processing" is started
* 2) The session is closed if an async request times out
*
* @author Rossen Stoyanchev
* @since 3.2.5
*/
public class AsyncRequestInterceptor extends CallableProcessingInterceptorAdapter
implements DeferredResultProcessingInterceptor {
private static Log logger = LogFactory.getLog(AsyncRequestInterceptor.class);
private final EntityManagerFactory emFactory;
private final EntityManagerHolder emHolder;
private volatile boolean timeoutInProgress;
public AsyncRequestInterceptor(EntityManagerFactory emFactory, EntityManagerHolder emHolder) {
this.emFactory = emFactory;
this.emHolder = emHolder;
}
@Override
public <T> void preProcess(NativeWebRequest request, Callable<T> task) {
bindSession();
}
public void bindSession() {
this.timeoutInProgress = false;
TransactionSynchronizationManager.bindResource(this.emFactory, this.emHolder);
}
@Override
public <T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) {
TransactionSynchronizationManager.unbindResource(this.emFactory);
}
@Override
public <T> Object handleTimeout(NativeWebRequest request, Callable<T> task) {
this.timeoutInProgress = true;
return RESULT_NONE; // give other interceptors a chance to handle the timeout
}
@Override
public <T> void afterCompletion(NativeWebRequest request, Callable<T> task) throws Exception {
closeAfterTimeout();
}
private void closeAfterTimeout() {
if (this.timeoutInProgress) {
logger.debug("Closing JPA EntityManager after async request timeout");
EntityManagerFactoryUtils.closeEntityManager(emHolder.getEntityManager());
}
}
// Implementation of DeferredResultProcessingInterceptor methods
public <T> void beforeConcurrentHandling(NativeWebRequest request, DeferredResult<T> deferredResult) { }
public <T> void preProcess(NativeWebRequest request, DeferredResult<T> deferredResult) { }
public <T> void postProcess(NativeWebRequest request, DeferredResult<T> deferredResult, Object result) { }
@Override
public <T> boolean handleTimeout(NativeWebRequest request, DeferredResult<T> deferredResult) {
this.timeoutInProgress = true;
return true; // give other interceptors a chance to handle the timeout
}
@Override
public <T> void afterCompletion(NativeWebRequest request, DeferredResult<T> deferredResult) {
closeAfterTimeout();
}
}

View File

@ -34,9 +34,7 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
import org.springframework.util.StringUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.async.CallableProcessingInterceptorAdapter;
import org.springframework.web.context.request.async.WebAsyncManager;
import org.springframework.web.context.request.async.WebAsyncUtils;
import org.springframework.web.context.request.async.*;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.OncePerRequestFilter;
@ -168,7 +166,9 @@ public class OpenEntityManagerInViewFilter extends OncePerRequestFilter {
EntityManagerHolder emHolder = new EntityManagerHolder(em);
TransactionSynchronizationManager.bindResource(emf, emHolder);
asyncManager.registerCallableInterceptor(key, new EntityManagerBindingCallableInterceptor(emf, emHolder));
AsyncRequestInterceptor interceptor = new AsyncRequestInterceptor(emf, emHolder);
asyncManager.registerCallableInterceptor(key, interceptor);
asyncManager.registerDeferredResultInterceptor(key, interceptor);
}
catch (PersistenceException ex) {
throw new DataAccessResourceFailureException("Could not create JPA EntityManager", ex);
@ -244,38 +244,8 @@ public class OpenEntityManagerInViewFilter extends OncePerRequestFilter {
if (asyncManager.getCallableInterceptor(key) == null) {
return false;
}
((EntityManagerBindingCallableInterceptor) asyncManager.getCallableInterceptor(key)).initializeThread();
((AsyncRequestInterceptor) asyncManager.getCallableInterceptor(key)).bindSession();
return true;
}
/**
* Bind and unbind the {@code EntityManager} to the current thread.
*/
private static class EntityManagerBindingCallableInterceptor extends CallableProcessingInterceptorAdapter {
private final EntityManagerFactory emFactory;
private final EntityManagerHolder emHolder;
public EntityManagerBindingCallableInterceptor(EntityManagerFactory emFactory, EntityManagerHolder emHolder) {
this.emFactory = emFactory;
this.emHolder = emHolder;
}
@Override
public <T> void preProcess(NativeWebRequest request, Callable<T> task) {
initializeThread();
}
@Override
public <T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) {
TransactionSynchronizationManager.unbindResource(this.emFactory);
}
private void initializeThread() {
TransactionSynchronizationManager.bindResource(this.emFactory, this.emHolder);
}
}
}

View File

@ -97,8 +97,9 @@ public class OpenEntityManagerInViewInterceptor extends EntityManagerFactoryAcce
EntityManagerHolder emHolder = new EntityManagerHolder(em);
TransactionSynchronizationManager.bindResource(getEntityManagerFactory(), emHolder);
asyncManager.registerCallableInterceptor(participateAttributeName,
new EntityManagerBindingCallableInterceptor(emHolder));
AsyncRequestInterceptor interceptor = new AsyncRequestInterceptor(getEntityManagerFactory(), emHolder);
asyncManager.registerCallableInterceptor(participateAttributeName, interceptor);
asyncManager.registerDeferredResultInterceptor(participateAttributeName, interceptor);
}
catch (PersistenceException ex) {
throw new DataAccessResourceFailureException("Could not create JPA EntityManager", ex);
@ -155,36 +156,8 @@ public class OpenEntityManagerInViewInterceptor extends EntityManagerFactoryAcce
if (asyncManager.getCallableInterceptor(key) == null) {
return false;
}
((EntityManagerBindingCallableInterceptor) asyncManager.getCallableInterceptor(key)).initializeThread();
((AsyncRequestInterceptor) asyncManager.getCallableInterceptor(key)).bindSession();
return true;
}
/**
* Bind and unbind the Hibernate {@code Session} to the current thread.
*/
private class EntityManagerBindingCallableInterceptor extends CallableProcessingInterceptorAdapter {
private final EntityManagerHolder emHolder;
public EntityManagerBindingCallableInterceptor(EntityManagerHolder emHolder) {
this.emHolder = emHolder;
}
@Override
public <T> void preProcess(NativeWebRequest request, Callable<T> task) {
initializeThread();
}
@Override
public <T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) {
TransactionSynchronizationManager.unbindResource(getEntityManagerFactory());
}
private void initializeThread() {
TransactionSynchronizationManager.bindResource(getEntityManagerFactory(), this.emHolder);
}
}
}

View File

@ -30,7 +30,9 @@ public abstract class DeferredResultProcessingInterceptorAdapter implements Defe
/**
* This implementation is empty.
*/
public <T> void beforeConcurrentHandling(NativeWebRequest request, DeferredResult<T> deferredResult) throws Exception {
@Override
public <T> void beforeConcurrentHandling(NativeWebRequest request, DeferredResult<T> deferredResult)
throws Exception {
}
/**
@ -47,7 +49,8 @@ public abstract class DeferredResultProcessingInterceptorAdapter implements Defe
}
/**
* This implementation returns {@code true} by default.
* This implementation returns {@code true} by default allowing other interceptors
* to be given a chance to handle the timeout.
*/
public <T> boolean handleTimeout(NativeWebRequest request, DeferredResult<T> deferredResult) throws Exception {
return true;