Skip to content

Commit 158b3c6

Browse files
committed
Merge pull request spring-projects#73 from rstoyanchev/mvc-async
HanderInterceptor and OSIV async request changes
2 parents 1eaaa9a + e7506b5 commit 158b3c6

File tree

12 files changed

+889
-358
lines changed

12 files changed

+889
-358
lines changed

spring-orm/src/main/java/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.java

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2009 the original author or authors.
2+
* Copyright 2002-2012 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -31,6 +31,8 @@
3131
import org.springframework.orm.hibernate3.SessionHolder;
3232
import org.springframework.transaction.support.TransactionSynchronizationManager;
3333
import org.springframework.web.context.WebApplicationContext;
34+
import org.springframework.web.context.request.async.AbstractDelegatingCallable;
35+
import org.springframework.web.context.request.async.AsyncExecutionChain;
3436
import org.springframework.web.context.support.WebApplicationContextUtils;
3537
import org.springframework.web.filter.OncePerRequestFilter;
3638

@@ -168,6 +170,8 @@ protected void doFilterInternal(
168170
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
169171
throws ServletException, IOException {
170172

173+
AsyncExecutionChain chain = AsyncExecutionChain.getForCurrentRequest(request);
174+
171175
SessionFactory sessionFactory = lookupSessionFactory(request);
172176
boolean participate = false;
173177

@@ -180,7 +184,10 @@ protected void doFilterInternal(
180184
else {
181185
logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");
182186
Session session = getSession(sessionFactory);
183-
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
187+
SessionHolder sessionHolder = new SessionHolder(session);
188+
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
189+
190+
chain.addDelegatingCallable(getAsyncCallable(request, sessionFactory, sessionHolder));
184191
}
185192
}
186193
else {
@@ -204,6 +211,9 @@ protected void doFilterInternal(
204211
// single session mode
205212
SessionHolder sessionHolder =
206213
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
214+
if (chain.isAsyncStarted()) {
215+
return;
216+
}
207217
logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");
208218
closeSession(sessionHolder.getSession(), sessionFactory);
209219
}
@@ -279,4 +289,28 @@ protected void closeSession(Session session, SessionFactory sessionFactory) {
279289
SessionFactoryUtils.closeSession(session);
280290
}
281291

292+
/**
293+
* Create a Callable to extend the use of the open Hibernate Session to the
294+
* async thread completing the request.
295+
*/
296+
private AbstractDelegatingCallable getAsyncCallable(final HttpServletRequest request,
297+
final SessionFactory sessionFactory, final SessionHolder sessionHolder) {
298+
299+
return new AbstractDelegatingCallable() {
300+
public Object call() throws Exception {
301+
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
302+
try {
303+
getNextCallable().call();
304+
}
305+
finally {
306+
SessionHolder sessionHolder =
307+
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
308+
logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
309+
SessionFactoryUtils.closeSession(sessionHolder.getSession());
310+
}
311+
return null;
312+
}
313+
};
314+
}
315+
282316
}

spring-orm/src/main/java/org/springframework/orm/hibernate3/support/OpenSessionInViewInterceptor.java

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2008 the original author or authors.
2+
* Copyright 2002-2012 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,15 +18,15 @@
1818

1919
import org.hibernate.HibernateException;
2020
import org.hibernate.Session;
21-
2221
import org.springframework.dao.DataAccessException;
2322
import org.springframework.orm.hibernate3.HibernateAccessor;
2423
import org.springframework.orm.hibernate3.SessionFactoryUtils;
2524
import org.springframework.orm.hibernate3.SessionHolder;
2625
import org.springframework.transaction.support.TransactionSynchronizationManager;
2726
import org.springframework.ui.ModelMap;
2827
import org.springframework.web.context.request.WebRequest;
29-
import org.springframework.web.context.request.WebRequestInterceptor;
28+
import org.springframework.web.context.request.async.AbstractDelegatingCallable;
29+
import org.springframework.web.context.request.async.AsyncWebRequestInterceptor;
3030

3131
/**
3232
* Spring web request interceptor that binds a Hibernate <code>Session</code> to the
@@ -89,7 +89,7 @@
8989
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession
9090
* @see org.springframework.transaction.support.TransactionSynchronizationManager
9191
*/
92-
public class OpenSessionInViewInterceptor extends HibernateAccessor implements WebRequestInterceptor {
92+
public class OpenSessionInViewInterceptor extends HibernateAccessor implements AsyncWebRequestInterceptor {
9393

9494
/**
9595
* Suffix that gets appended to the <code>SessionFactory</code>
@@ -155,7 +155,8 @@ public void preHandle(WebRequest request) throws DataAccessException {
155155
Session session = SessionFactoryUtils.getSession(
156156
getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());
157157
applyFlushMode(session, false);
158-
TransactionSynchronizationManager.bindResource(getSessionFactory(), new SessionHolder(session));
158+
SessionHolder sessionHolder = new SessionHolder(session);
159+
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
159160
}
160161
else {
161162
// deferred close mode
@@ -164,6 +165,39 @@ public void preHandle(WebRequest request) throws DataAccessException {
164165
}
165166
}
166167

168+
/**
169+
* Create a <code>Callable</code> to bind the <code>Hibernate</code> session
170+
* to the async request thread.
171+
*/
172+
public AbstractDelegatingCallable getAsyncCallable(WebRequest request) {
173+
String attributeName = getParticipateAttributeName();
174+
if ((request.getAttribute(attributeName, WebRequest.SCOPE_REQUEST) != null) || !isSingleSession()) {
175+
return null;
176+
}
177+
178+
final SessionHolder sessionHolder =
179+
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
180+
181+
return new AbstractDelegatingCallable() {
182+
public Object call() throws Exception {
183+
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
184+
getNextCallable().call();
185+
return null;
186+
}
187+
};
188+
}
189+
190+
/**
191+
* Unbind the Hibernate <code>Session</code> from the main thread but leave
192+
* the <code>Session</code> open for further use from the async thread.
193+
*/
194+
public void postHandleAsyncStarted(WebRequest request) {
195+
String attributeName = getParticipateAttributeName();
196+
if ((request.getAttribute(attributeName, WebRequest.SCOPE_REQUEST) == null) && isSingleSession()) {
197+
TransactionSynchronizationManager.unbindResource(getSessionFactory());
198+
}
199+
}
200+
167201
/**
168202
* Flush the Hibernate <code>Session</code> before view rendering, if necessary.
169203
* <p>Note that this just applies in {@link #isSingleSession() single session mode}!

spring-orm/src/main/java/org/springframework/orm/hibernate4/support/OpenSessionInViewFilter.java

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2011 the original author or authors.
2+
* Copyright 2002-2012 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -32,6 +32,8 @@
3232
import org.springframework.orm.hibernate4.SessionHolder;
3333
import org.springframework.transaction.support.TransactionSynchronizationManager;
3434
import org.springframework.web.context.WebApplicationContext;
35+
import org.springframework.web.context.request.async.AbstractDelegatingCallable;
36+
import org.springframework.web.context.request.async.AsyncExecutionChain;
3537
import org.springframework.web.context.support.WebApplicationContextUtils;
3638
import org.springframework.web.filter.OncePerRequestFilter;
3739

@@ -102,6 +104,8 @@ protected void doFilterInternal(
102104
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
103105
throws ServletException, IOException {
104106

107+
AsyncExecutionChain chain = AsyncExecutionChain.getForCurrentRequest(request);
108+
105109
SessionFactory sessionFactory = lookupSessionFactory(request);
106110
boolean participate = false;
107111

@@ -112,7 +116,10 @@ protected void doFilterInternal(
112116
else {
113117
logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");
114118
Session session = openSession(sessionFactory);
115-
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
119+
SessionHolder sessionHolder = new SessionHolder(session);
120+
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
121+
122+
chain.addDelegatingCallable(getAsyncCallable(request, sessionFactory, sessionHolder));
116123
}
117124

118125
try {
@@ -123,6 +130,9 @@ protected void doFilterInternal(
123130
if (!participate) {
124131
SessionHolder sessionHolder =
125132
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
133+
if (chain.isAsyncStarted()) {
134+
return;
135+
}
126136
logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
127137
SessionFactoryUtils.closeSession(sessionHolder.getSession());
128138
}
@@ -177,4 +187,28 @@ protected Session openSession(SessionFactory sessionFactory) throws DataAccessRe
177187
}
178188
}
179189

190+
/**
191+
* Create a Callable to extend the use of the open Hibernate Session to the
192+
* async thread completing the request.
193+
*/
194+
private AbstractDelegatingCallable getAsyncCallable(final HttpServletRequest request,
195+
final SessionFactory sessionFactory, final SessionHolder sessionHolder) {
196+
197+
return new AbstractDelegatingCallable() {
198+
public Object call() throws Exception {
199+
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
200+
try {
201+
getNextCallable().call();
202+
}
203+
finally {
204+
SessionHolder sessionHolder =
205+
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
206+
logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
207+
SessionFactoryUtils.closeSession(sessionHolder.getSession());
208+
}
209+
return null;
210+
}
211+
};
212+
}
213+
180214
}

spring-orm/src/main/java/org/springframework/orm/hibernate4/support/OpenSessionInViewInterceptor.java

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2011 the original author or authors.
2+
* Copyright 2002-2012 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,15 +22,16 @@
2222
import org.hibernate.HibernateException;
2323
import org.hibernate.Session;
2424
import org.hibernate.SessionFactory;
25-
2625
import org.springframework.dao.DataAccessException;
2726
import org.springframework.dao.DataAccessResourceFailureException;
2827
import org.springframework.orm.hibernate4.SessionFactoryUtils;
2928
import org.springframework.orm.hibernate4.SessionHolder;
3029
import org.springframework.transaction.support.TransactionSynchronizationManager;
3130
import org.springframework.ui.ModelMap;
3231
import org.springframework.web.context.request.WebRequest;
33-
import org.springframework.web.context.request.WebRequestInterceptor;
32+
import org.springframework.web.context.request.async.AbstractDelegatingCallable;
33+
import org.springframework.web.context.request.async.AsyncExecutionChain;
34+
import org.springframework.web.context.request.async.AsyncWebRequestInterceptor;
3435

3536
/**
3637
* Spring web request interceptor that binds a Hibernate <code>Session</code> to the
@@ -72,7 +73,7 @@
7273
* @see org.springframework.orm.hibernate4.HibernateTransactionManager
7374
* @see org.springframework.transaction.support.TransactionSynchronizationManager
7475
*/
75-
public class OpenSessionInViewInterceptor implements WebRequestInterceptor {
76+
public class OpenSessionInViewInterceptor implements AsyncWebRequestInterceptor {
7677

7778
/**
7879
* Suffix that gets appended to the <code>SessionFactory</code>
@@ -112,13 +113,47 @@ public void preHandle(WebRequest request) throws DataAccessException {
112113
else {
113114
logger.debug("Opening Hibernate Session in OpenSessionInViewInterceptor");
114115
Session session = openSession();
115-
TransactionSynchronizationManager.bindResource(getSessionFactory(), new SessionHolder(session));
116+
SessionHolder sessionHolder = new SessionHolder(session);
117+
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
116118
}
117119
}
118120

119121
public void postHandle(WebRequest request, ModelMap model) {
120122
}
121123

124+
/**
125+
* Create a <code>Callable</code> to bind the <code>Hibernate</code> session
126+
* to the async request thread.
127+
*/
128+
public AbstractDelegatingCallable getAsyncCallable(WebRequest request) {
129+
String attributeName = getParticipateAttributeName();
130+
if (request.getAttribute(attributeName, WebRequest.SCOPE_REQUEST) != null) {
131+
return null;
132+
}
133+
134+
final SessionHolder sessionHolder =
135+
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
136+
137+
return new AbstractDelegatingCallable() {
138+
public Object call() throws Exception {
139+
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
140+
getNextCallable().call();
141+
return null;
142+
}
143+
};
144+
}
145+
146+
/**
147+
* Unbind the Hibernate <code>Session</code> from the main thread leaving
148+
* it open for further use from an async thread.
149+
*/
150+
public void postHandleAsyncStarted(WebRequest request) {
151+
String attributeName = getParticipateAttributeName();
152+
if (request.getAttribute(attributeName, WebRequest.SCOPE_REQUEST) == null) {
153+
TransactionSynchronizationManager.unbindResource(getSessionFactory());
154+
}
155+
}
156+
122157
/**
123158
* Unbind the Hibernate <code>Session</code> from the thread and close it).
124159
* @see org.springframework.transaction.support.TransactionSynchronizationManager

0 commit comments

Comments
 (0)