Merge pull request #73 from rstoyanchev/mvc-async
HanderInterceptor and OSIV async request changes
This commit is contained in:
commit
158b3c6af8
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2009 the original author or authors.
|
* Copyright 2002-2012 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -31,6 +31,8 @@ import org.springframework.orm.hibernate3.SessionFactoryUtils;
|
||||||
import org.springframework.orm.hibernate3.SessionHolder;
|
import org.springframework.orm.hibernate3.SessionHolder;
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||||
import org.springframework.web.context.WebApplicationContext;
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
|
import org.springframework.web.context.request.async.AbstractDelegatingCallable;
|
||||||
|
import org.springframework.web.context.request.async.AsyncExecutionChain;
|
||||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
|
@ -168,6 +170,8 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
|
||||||
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
|
|
||||||
|
AsyncExecutionChain chain = AsyncExecutionChain.getForCurrentRequest(request);
|
||||||
|
|
||||||
SessionFactory sessionFactory = lookupSessionFactory(request);
|
SessionFactory sessionFactory = lookupSessionFactory(request);
|
||||||
boolean participate = false;
|
boolean participate = false;
|
||||||
|
|
||||||
|
|
@ -180,7 +184,10 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
|
||||||
else {
|
else {
|
||||||
logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");
|
logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");
|
||||||
Session session = getSession(sessionFactory);
|
Session session = getSession(sessionFactory);
|
||||||
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
|
SessionHolder sessionHolder = new SessionHolder(session);
|
||||||
|
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
|
||||||
|
|
||||||
|
chain.addDelegatingCallable(getAsyncCallable(request, sessionFactory, sessionHolder));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -204,6 +211,9 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
|
||||||
// single session mode
|
// single session mode
|
||||||
SessionHolder sessionHolder =
|
SessionHolder sessionHolder =
|
||||||
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
|
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
|
||||||
|
if (chain.isAsyncStarted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");
|
logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");
|
||||||
closeSession(sessionHolder.getSession(), sessionFactory);
|
closeSession(sessionHolder.getSession(), sessionFactory);
|
||||||
}
|
}
|
||||||
|
|
@ -279,4 +289,28 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
|
||||||
SessionFactoryUtils.closeSession(session);
|
SessionFactoryUtils.closeSession(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Callable to extend the use of the open Hibernate Session to the
|
||||||
|
* async thread completing the request.
|
||||||
|
*/
|
||||||
|
private AbstractDelegatingCallable getAsyncCallable(final HttpServletRequest request,
|
||||||
|
final SessionFactory sessionFactory, final SessionHolder sessionHolder) {
|
||||||
|
|
||||||
|
return new AbstractDelegatingCallable() {
|
||||||
|
public Object call() throws Exception {
|
||||||
|
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
|
||||||
|
try {
|
||||||
|
getNextCallable().call();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
SessionHolder sessionHolder =
|
||||||
|
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
|
||||||
|
logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
|
||||||
|
SessionFactoryUtils.closeSession(sessionHolder.getSession());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2012 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -18,7 +18,6 @@ package org.springframework.orm.hibernate3.support;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
|
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.orm.hibernate3.HibernateAccessor;
|
import org.springframework.orm.hibernate3.HibernateAccessor;
|
||||||
import org.springframework.orm.hibernate3.SessionFactoryUtils;
|
import org.springframework.orm.hibernate3.SessionFactoryUtils;
|
||||||
|
|
@ -26,7 +25,8 @@ import org.springframework.orm.hibernate3.SessionHolder;
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||||
import org.springframework.ui.ModelMap;
|
import org.springframework.ui.ModelMap;
|
||||||
import org.springframework.web.context.request.WebRequest;
|
import org.springframework.web.context.request.WebRequest;
|
||||||
import org.springframework.web.context.request.WebRequestInterceptor;
|
import org.springframework.web.context.request.async.AbstractDelegatingCallable;
|
||||||
|
import org.springframework.web.context.request.async.AsyncWebRequestInterceptor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spring web request interceptor that binds a Hibernate <code>Session</code> to the
|
* Spring web request interceptor that binds a Hibernate <code>Session</code> to the
|
||||||
|
|
@ -89,7 +89,7 @@ import org.springframework.web.context.request.WebRequestInterceptor;
|
||||||
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession
|
* @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession
|
||||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
||||||
*/
|
*/
|
||||||
public class OpenSessionInViewInterceptor extends HibernateAccessor implements WebRequestInterceptor {
|
public class OpenSessionInViewInterceptor extends HibernateAccessor implements AsyncWebRequestInterceptor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Suffix that gets appended to the <code>SessionFactory</code>
|
* Suffix that gets appended to the <code>SessionFactory</code>
|
||||||
|
|
@ -155,7 +155,8 @@ public class OpenSessionInViewInterceptor extends HibernateAccessor implements W
|
||||||
Session session = SessionFactoryUtils.getSession(
|
Session session = SessionFactoryUtils.getSession(
|
||||||
getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());
|
getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());
|
||||||
applyFlushMode(session, false);
|
applyFlushMode(session, false);
|
||||||
TransactionSynchronizationManager.bindResource(getSessionFactory(), new SessionHolder(session));
|
SessionHolder sessionHolder = new SessionHolder(session);
|
||||||
|
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// deferred close mode
|
// deferred close mode
|
||||||
|
|
@ -164,6 +165,39 @@ public class OpenSessionInViewInterceptor extends HibernateAccessor implements W
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a <code>Callable</code> to bind the <code>Hibernate</code> session
|
||||||
|
* to the async request thread.
|
||||||
|
*/
|
||||||
|
public AbstractDelegatingCallable getAsyncCallable(WebRequest request) {
|
||||||
|
String attributeName = getParticipateAttributeName();
|
||||||
|
if ((request.getAttribute(attributeName, WebRequest.SCOPE_REQUEST) != null) || !isSingleSession()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final SessionHolder sessionHolder =
|
||||||
|
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
|
||||||
|
|
||||||
|
return new AbstractDelegatingCallable() {
|
||||||
|
public Object call() throws Exception {
|
||||||
|
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
|
||||||
|
getNextCallable().call();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unbind the Hibernate <code>Session</code> from the main thread but leave
|
||||||
|
* the <code>Session</code> open for further use from the async thread.
|
||||||
|
*/
|
||||||
|
public void postHandleAsyncStarted(WebRequest request) {
|
||||||
|
String attributeName = getParticipateAttributeName();
|
||||||
|
if ((request.getAttribute(attributeName, WebRequest.SCOPE_REQUEST) == null) && isSingleSession()) {
|
||||||
|
TransactionSynchronizationManager.unbindResource(getSessionFactory());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flush the Hibernate <code>Session</code> before view rendering, if necessary.
|
* Flush the Hibernate <code>Session</code> before view rendering, if necessary.
|
||||||
* <p>Note that this just applies in {@link #isSingleSession() single session mode}!
|
* <p>Note that this just applies in {@link #isSingleSession() single session mode}!
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2011 the original author or authors.
|
* Copyright 2002-2012 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -32,6 +32,8 @@ import org.springframework.orm.hibernate4.SessionFactoryUtils;
|
||||||
import org.springframework.orm.hibernate4.SessionHolder;
|
import org.springframework.orm.hibernate4.SessionHolder;
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||||
import org.springframework.web.context.WebApplicationContext;
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
|
import org.springframework.web.context.request.async.AbstractDelegatingCallable;
|
||||||
|
import org.springframework.web.context.request.async.AsyncExecutionChain;
|
||||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
|
@ -102,6 +104,8 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
|
||||||
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
|
|
||||||
|
AsyncExecutionChain chain = AsyncExecutionChain.getForCurrentRequest(request);
|
||||||
|
|
||||||
SessionFactory sessionFactory = lookupSessionFactory(request);
|
SessionFactory sessionFactory = lookupSessionFactory(request);
|
||||||
boolean participate = false;
|
boolean participate = false;
|
||||||
|
|
||||||
|
|
@ -112,7 +116,10 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
|
||||||
else {
|
else {
|
||||||
logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");
|
logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");
|
||||||
Session session = openSession(sessionFactory);
|
Session session = openSession(sessionFactory);
|
||||||
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
|
SessionHolder sessionHolder = new SessionHolder(session);
|
||||||
|
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
|
||||||
|
|
||||||
|
chain.addDelegatingCallable(getAsyncCallable(request, sessionFactory, sessionHolder));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -123,6 +130,9 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
|
||||||
if (!participate) {
|
if (!participate) {
|
||||||
SessionHolder sessionHolder =
|
SessionHolder sessionHolder =
|
||||||
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
|
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
|
||||||
|
if (chain.isAsyncStarted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
|
logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
|
||||||
SessionFactoryUtils.closeSession(sessionHolder.getSession());
|
SessionFactoryUtils.closeSession(sessionHolder.getSession());
|
||||||
}
|
}
|
||||||
|
|
@ -177,4 +187,28 @@ public class OpenSessionInViewFilter extends OncePerRequestFilter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Callable to extend the use of the open Hibernate Session to the
|
||||||
|
* async thread completing the request.
|
||||||
|
*/
|
||||||
|
private AbstractDelegatingCallable getAsyncCallable(final HttpServletRequest request,
|
||||||
|
final SessionFactory sessionFactory, final SessionHolder sessionHolder) {
|
||||||
|
|
||||||
|
return new AbstractDelegatingCallable() {
|
||||||
|
public Object call() throws Exception {
|
||||||
|
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
|
||||||
|
try {
|
||||||
|
getNextCallable().call();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
SessionHolder sessionHolder =
|
||||||
|
(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
|
||||||
|
logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
|
||||||
|
SessionFactoryUtils.closeSession(sessionHolder.getSession());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2011 the original author or authors.
|
* Copyright 2002-2012 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -22,7 +22,6 @@ import org.hibernate.FlushMode;
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.SessionFactory;
|
import org.hibernate.SessionFactory;
|
||||||
|
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.dao.DataAccessResourceFailureException;
|
import org.springframework.dao.DataAccessResourceFailureException;
|
||||||
import org.springframework.orm.hibernate4.SessionFactoryUtils;
|
import org.springframework.orm.hibernate4.SessionFactoryUtils;
|
||||||
|
|
@ -30,7 +29,9 @@ import org.springframework.orm.hibernate4.SessionHolder;
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||||
import org.springframework.ui.ModelMap;
|
import org.springframework.ui.ModelMap;
|
||||||
import org.springframework.web.context.request.WebRequest;
|
import org.springframework.web.context.request.WebRequest;
|
||||||
import org.springframework.web.context.request.WebRequestInterceptor;
|
import org.springframework.web.context.request.async.AbstractDelegatingCallable;
|
||||||
|
import org.springframework.web.context.request.async.AsyncExecutionChain;
|
||||||
|
import org.springframework.web.context.request.async.AsyncWebRequestInterceptor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spring web request interceptor that binds a Hibernate <code>Session</code> to the
|
* Spring web request interceptor that binds a Hibernate <code>Session</code> to the
|
||||||
|
|
@ -72,7 +73,7 @@ import org.springframework.web.context.request.WebRequestInterceptor;
|
||||||
* @see org.springframework.orm.hibernate4.HibernateTransactionManager
|
* @see org.springframework.orm.hibernate4.HibernateTransactionManager
|
||||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
||||||
*/
|
*/
|
||||||
public class OpenSessionInViewInterceptor implements WebRequestInterceptor {
|
public class OpenSessionInViewInterceptor implements AsyncWebRequestInterceptor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Suffix that gets appended to the <code>SessionFactory</code>
|
* Suffix that gets appended to the <code>SessionFactory</code>
|
||||||
|
|
@ -112,13 +113,47 @@ public class OpenSessionInViewInterceptor implements WebRequestInterceptor {
|
||||||
else {
|
else {
|
||||||
logger.debug("Opening Hibernate Session in OpenSessionInViewInterceptor");
|
logger.debug("Opening Hibernate Session in OpenSessionInViewInterceptor");
|
||||||
Session session = openSession();
|
Session session = openSession();
|
||||||
TransactionSynchronizationManager.bindResource(getSessionFactory(), new SessionHolder(session));
|
SessionHolder sessionHolder = new SessionHolder(session);
|
||||||
|
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void postHandle(WebRequest request, ModelMap model) {
|
public void postHandle(WebRequest request, ModelMap model) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a <code>Callable</code> to bind the <code>Hibernate</code> session
|
||||||
|
* to the async request thread.
|
||||||
|
*/
|
||||||
|
public AbstractDelegatingCallable getAsyncCallable(WebRequest request) {
|
||||||
|
String attributeName = getParticipateAttributeName();
|
||||||
|
if (request.getAttribute(attributeName, WebRequest.SCOPE_REQUEST) != null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final SessionHolder sessionHolder =
|
||||||
|
(SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
|
||||||
|
|
||||||
|
return new AbstractDelegatingCallable() {
|
||||||
|
public Object call() throws Exception {
|
||||||
|
TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
|
||||||
|
getNextCallable().call();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unbind the Hibernate <code>Session</code> from the main thread leaving
|
||||||
|
* it open for further use from an async thread.
|
||||||
|
*/
|
||||||
|
public void postHandleAsyncStarted(WebRequest request) {
|
||||||
|
String attributeName = getParticipateAttributeName();
|
||||||
|
if (request.getAttribute(attributeName, WebRequest.SCOPE_REQUEST) == null) {
|
||||||
|
TransactionSynchronizationManager.unbindResource(getSessionFactory());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unbind the Hibernate <code>Session</code> from the thread and close it).
|
* Unbind the Hibernate <code>Session</code> from the thread and close it).
|
||||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
* @see org.springframework.transaction.support.TransactionSynchronizationManager
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2011 the original author or authors.
|
* Copyright 2002-2012 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -16,23 +16,35 @@
|
||||||
|
|
||||||
package org.springframework.orm.hibernate3.support;
|
package org.springframework.orm.hibernate3.support;
|
||||||
|
|
||||||
|
import static org.easymock.EasyMock.createStrictMock;
|
||||||
|
import static org.easymock.EasyMock.expect;
|
||||||
|
import static org.easymock.EasyMock.replay;
|
||||||
|
import static org.easymock.EasyMock.reset;
|
||||||
|
import static org.easymock.EasyMock.verify;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
import javax.servlet.FilterChain;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
import javax.transaction.TransactionManager;
|
import javax.transaction.TransactionManager;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
import org.easymock.MockControl;
|
|
||||||
import org.hibernate.FlushMode;
|
import org.hibernate.FlushMode;
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.SessionFactory;
|
import org.hibernate.SessionFactory;
|
||||||
import org.hibernate.Transaction;
|
import org.hibernate.Transaction;
|
||||||
import org.hibernate.classic.Session;
|
import org.hibernate.classic.Session;
|
||||||
import org.hibernate.engine.SessionFactoryImplementor;
|
import org.hibernate.engine.SessionFactoryImplementor;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||||
import org.springframework.mock.web.MockFilterConfig;
|
import org.springframework.mock.web.MockFilterConfig;
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.mock.web.MockHttpServletResponse;
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
|
|
@ -47,307 +59,341 @@ import org.springframework.transaction.support.DefaultTransactionDefinition;
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||||
import org.springframework.web.context.WebApplicationContext;
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
import org.springframework.web.context.request.ServletWebRequest;
|
import org.springframework.web.context.request.ServletWebRequest;
|
||||||
|
import org.springframework.web.context.request.async.AbstractDelegatingCallable;
|
||||||
|
import org.springframework.web.context.request.async.AsyncExecutionChain;
|
||||||
|
import org.springframework.web.context.request.async.AsyncWebRequest;
|
||||||
import org.springframework.web.context.support.StaticWebApplicationContext;
|
import org.springframework.web.context.support.StaticWebApplicationContext;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
* @author Rossen Stoyanchev
|
||||||
* @since 05.03.2005
|
* @since 05.03.2005
|
||||||
*/
|
*/
|
||||||
public class OpenSessionInViewTests extends TestCase {
|
public class OpenSessionInViewTests {
|
||||||
|
|
||||||
|
private MockServletContext sc;
|
||||||
|
|
||||||
|
private MockHttpServletRequest request;
|
||||||
|
|
||||||
|
private MockHttpServletResponse response;
|
||||||
|
|
||||||
|
private ServletWebRequest webRequest;
|
||||||
|
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
this.sc = new MockServletContext();
|
||||||
|
this.request = new MockHttpServletRequest(sc);
|
||||||
|
this.response = new MockHttpServletResponse();
|
||||||
|
this.webRequest = new ServletWebRequest(this.request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testOpenSessionInViewInterceptorWithSingleSession() throws Exception {
|
public void testOpenSessionInViewInterceptorWithSingleSession() throws Exception {
|
||||||
|
|
||||||
//SessionFactory sf = createMock(SessionFactory.class);
|
SessionFactory sf = createStrictMock(SessionFactory.class);
|
||||||
//Session session = createMock(Session.class);
|
Session session = createStrictMock(Session.class);
|
||||||
|
|
||||||
MockControl sfControl = MockControl.createControl(SessionFactory.class);
|
|
||||||
final SessionFactory sf = (SessionFactory) sfControl.getMock();
|
|
||||||
MockControl sessionControl = MockControl.createControl(Session.class);
|
|
||||||
Session session = (Session) sessionControl.getMock();
|
|
||||||
|
|
||||||
OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor();
|
OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor();
|
||||||
interceptor.setSessionFactory(sf);
|
interceptor.setSessionFactory(sf);
|
||||||
|
|
||||||
MockServletContext sc = new MockServletContext();
|
expect(sf.openSession()).andReturn(session);
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest(sc);
|
expect(session.getSessionFactory()).andReturn(sf);
|
||||||
|
|
||||||
//expect(mockStorage.size()).andReturn(expectedValue);
|
|
||||||
|
|
||||||
//expect(sf.openSession()).andReturn(session);
|
|
||||||
sf.openSession();
|
|
||||||
sfControl.setReturnValue(session, 1);
|
|
||||||
session.getSessionFactory();
|
|
||||||
sessionControl.setReturnValue(sf, 2);
|
|
||||||
session.isOpen();
|
|
||||||
sessionControl.setReturnValue(true, 1);
|
|
||||||
session.setFlushMode(FlushMode.MANUAL);
|
session.setFlushMode(FlushMode.MANUAL);
|
||||||
sessionControl.setVoidCallable(1);
|
expect(session.getSessionFactory()).andReturn(sf);
|
||||||
sfControl.replay();
|
expect(session.isOpen()).andReturn(true);
|
||||||
sessionControl.replay();
|
replay(sf);
|
||||||
interceptor.preHandle(new ServletWebRequest(request));
|
replay(session);
|
||||||
|
|
||||||
|
interceptor.preHandle(this.webRequest);
|
||||||
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||||
|
|
||||||
// check that further invocations simply participate
|
// check that further invocations simply participate
|
||||||
interceptor.preHandle(new ServletWebRequest(request));
|
interceptor.preHandle(this.webRequest);
|
||||||
|
|
||||||
assertEquals(session, SessionFactoryUtils.getSession(sf, false));
|
assertEquals(session, SessionFactoryUtils.getSession(sf, false));
|
||||||
|
|
||||||
interceptor.preHandle(new ServletWebRequest(request));
|
interceptor.preHandle(this.webRequest);
|
||||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
interceptor.postHandle(this.webRequest, null);
|
||||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
interceptor.afterCompletion(this.webRequest, null);
|
||||||
|
|
||||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
interceptor.postHandle(this.webRequest, null);
|
||||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
interceptor.afterCompletion(this.webRequest, null);
|
||||||
|
|
||||||
interceptor.preHandle(new ServletWebRequest(request));
|
interceptor.preHandle(this.webRequest);
|
||||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
interceptor.postHandle(this.webRequest, null);
|
||||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
interceptor.afterCompletion(this.webRequest, null);
|
||||||
|
|
||||||
sfControl.verify();
|
verify(sf);
|
||||||
sessionControl.verify();
|
verify(session);
|
||||||
|
reset(sf);
|
||||||
|
reset(session);
|
||||||
|
replay(sf);
|
||||||
|
replay(session);
|
||||||
|
|
||||||
sfControl.reset();
|
interceptor.postHandle(this.webRequest, null);
|
||||||
sessionControl.reset();
|
|
||||||
sfControl.replay();
|
|
||||||
sessionControl.replay();
|
|
||||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
|
||||||
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||||
sfControl.verify();
|
|
||||||
sessionControl.verify();
|
|
||||||
|
|
||||||
sfControl.reset();
|
verify(sf);
|
||||||
sessionControl.reset();
|
verify(session);
|
||||||
session.close();
|
reset(sf);
|
||||||
sessionControl.setReturnValue(null, 1);
|
reset(session);
|
||||||
sfControl.replay();
|
expect(session.close()).andReturn(null);
|
||||||
sessionControl.replay();
|
replay(sf);
|
||||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
replay(session);
|
||||||
|
|
||||||
|
interceptor.afterCompletion(this.webRequest, null);
|
||||||
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
||||||
sfControl.verify();
|
|
||||||
sessionControl.verify();
|
verify(sf);
|
||||||
|
verify(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOpenSessionInViewInterceptorAsyncScenario() throws Exception {
|
||||||
|
|
||||||
|
final SessionFactory sf = createStrictMock(SessionFactory.class);
|
||||||
|
Session session = createStrictMock(Session.class);
|
||||||
|
|
||||||
|
OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor();
|
||||||
|
interceptor.setSessionFactory(sf);
|
||||||
|
|
||||||
|
expect(sf.openSession()).andReturn(session);
|
||||||
|
expect(session.getSessionFactory()).andReturn(sf);
|
||||||
|
session.setFlushMode(FlushMode.MANUAL);
|
||||||
|
replay(sf);
|
||||||
|
replay(session);
|
||||||
|
|
||||||
|
interceptor.preHandle(this.webRequest);
|
||||||
|
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||||
|
|
||||||
|
AbstractDelegatingCallable asyncCallable = interceptor.getAsyncCallable(this.webRequest);
|
||||||
|
assertNotNull(asyncCallable);
|
||||||
|
|
||||||
|
interceptor.postHandleAsyncStarted(this.webRequest);
|
||||||
|
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
||||||
|
|
||||||
|
verify(sf);
|
||||||
|
verify(session);
|
||||||
|
|
||||||
|
asyncCallable.setNextCallable(new Callable<Object>() {
|
||||||
|
public Object call() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
asyncCallable.call();
|
||||||
|
assertTrue("Session not bound to async thread", TransactionSynchronizationManager.hasResource(sf));
|
||||||
|
|
||||||
|
verify(sf);
|
||||||
|
verify(session);
|
||||||
|
reset(sf);
|
||||||
|
reset(session);
|
||||||
|
replay(sf);
|
||||||
|
replay(session);
|
||||||
|
|
||||||
|
interceptor.postHandle(this.webRequest, null);
|
||||||
|
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||||
|
|
||||||
|
verify(sf);
|
||||||
|
verify(session);
|
||||||
|
reset(sf);
|
||||||
|
reset(session);
|
||||||
|
expect(session.close()).andReturn(null);
|
||||||
|
replay(sf);
|
||||||
|
replay(session);
|
||||||
|
|
||||||
|
interceptor.afterCompletion(this.webRequest, null);
|
||||||
|
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
||||||
|
|
||||||
|
verify(sf);
|
||||||
|
verify(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testOpenSessionInViewInterceptorWithSingleSessionAndJtaTm() throws Exception {
|
public void testOpenSessionInViewInterceptorWithSingleSessionAndJtaTm() throws Exception {
|
||||||
MockControl sfControl = MockControl.createControl(SessionFactoryImplementor.class);
|
final SessionFactoryImplementor sf = createStrictMock(SessionFactoryImplementor.class);
|
||||||
final SessionFactoryImplementor sf = (SessionFactoryImplementor) sfControl.getMock();
|
Session session = createStrictMock(Session.class);
|
||||||
MockControl sessionControl = MockControl.createControl(Session.class);
|
|
||||||
Session session = (Session) sessionControl.getMock();
|
|
||||||
|
|
||||||
MockControl tmControl = MockControl.createControl(TransactionManager.class);
|
TransactionManager tm = createStrictMock(TransactionManager.class);
|
||||||
TransactionManager tm = (TransactionManager) tmControl.getMock();
|
expect(tm.getTransaction()).andReturn(null);
|
||||||
tm.getTransaction();
|
expect(tm.getTransaction()).andReturn(null);
|
||||||
tmControl.setReturnValue(null, 2);
|
replay(tm);
|
||||||
|
|
||||||
OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor();
|
OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor();
|
||||||
interceptor.setSessionFactory(sf);
|
interceptor.setSessionFactory(sf);
|
||||||
|
|
||||||
MockServletContext sc = new MockServletContext();
|
expect(sf.openSession()).andReturn(session);
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest(sc);
|
expect(sf.getTransactionManager()).andReturn(tm);
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
|
||||||
|
|
||||||
sf.getTransactionManager();
|
|
||||||
sfControl.setReturnValue(tm, 2);
|
|
||||||
sf.openSession();
|
|
||||||
sfControl.setReturnValue(session, 1);
|
|
||||||
session.isOpen();
|
|
||||||
sessionControl.setReturnValue(true, 1);
|
|
||||||
session.setFlushMode(FlushMode.MANUAL);
|
session.setFlushMode(FlushMode.MANUAL);
|
||||||
sessionControl.setVoidCallable(1);
|
expect(sf.getTransactionManager()).andReturn(tm);
|
||||||
|
expect(session.isOpen()).andReturn(true);
|
||||||
|
|
||||||
tmControl.replay();
|
replay(sf);
|
||||||
sfControl.replay();
|
replay(session);
|
||||||
sessionControl.replay();
|
|
||||||
|
|
||||||
interceptor.preHandle(new ServletWebRequest(request));
|
interceptor.preHandle(this.webRequest);
|
||||||
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||||
|
|
||||||
// check that further invocations simply participate
|
// check that further invocations simply participate
|
||||||
interceptor.preHandle(new ServletWebRequest(request));
|
interceptor.preHandle(this.webRequest);
|
||||||
|
|
||||||
assertEquals(session, SessionFactoryUtils.getSession(sf, false));
|
assertEquals(session, SessionFactoryUtils.getSession(sf, false));
|
||||||
|
|
||||||
interceptor.preHandle(new ServletWebRequest(request));
|
interceptor.preHandle(this.webRequest);
|
||||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
interceptor.postHandle(this.webRequest, null);
|
||||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
interceptor.afterCompletion(this.webRequest, null);
|
||||||
|
|
||||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
interceptor.postHandle(this.webRequest, null);
|
||||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
interceptor.afterCompletion(this.webRequest, null);
|
||||||
|
|
||||||
interceptor.preHandle(new ServletWebRequest(request));
|
interceptor.preHandle(this.webRequest);
|
||||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
interceptor.postHandle(this.webRequest, null);
|
||||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
interceptor.afterCompletion(this.webRequest, null);
|
||||||
|
|
||||||
sfControl.verify();
|
verify(sf);
|
||||||
sessionControl.verify();
|
verify(session);
|
||||||
|
|
||||||
sfControl.reset();
|
reset(sf);
|
||||||
sessionControl.reset();
|
reset(session);
|
||||||
sfControl.replay();
|
replay(sf);
|
||||||
sessionControl.replay();
|
replay(session);
|
||||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
|
||||||
|
interceptor.postHandle(this.webRequest, null);
|
||||||
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||||
sfControl.verify();
|
|
||||||
sessionControl.verify();
|
|
||||||
|
|
||||||
sfControl.reset();
|
verify(sf);
|
||||||
sessionControl.reset();
|
verify(session);
|
||||||
session.close();
|
|
||||||
sessionControl.setReturnValue(null, 1);
|
reset(sf);
|
||||||
sfControl.replay();
|
reset(session);
|
||||||
sessionControl.replay();
|
expect(session.close()).andReturn(null);
|
||||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
replay(sf);
|
||||||
|
replay(session);
|
||||||
|
|
||||||
|
interceptor.afterCompletion(this.webRequest, null);
|
||||||
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
||||||
sfControl.verify();
|
|
||||||
sessionControl.verify();
|
verify(sf);
|
||||||
|
verify(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testOpenSessionInViewInterceptorWithSingleSessionAndFlush() throws Exception {
|
public void testOpenSessionInViewInterceptorWithSingleSessionAndFlush() throws Exception {
|
||||||
MockControl sfControl = MockControl.createControl(SessionFactory.class);
|
SessionFactory sf = createStrictMock(SessionFactory.class);
|
||||||
final SessionFactory sf = (SessionFactory) sfControl.getMock();
|
Session session = createStrictMock(Session.class);
|
||||||
MockControl sessionControl = MockControl.createControl(Session.class);
|
|
||||||
Session session = (Session) sessionControl.getMock();
|
|
||||||
|
|
||||||
OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor();
|
OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor();
|
||||||
interceptor.setSessionFactory(sf);
|
interceptor.setSessionFactory(sf);
|
||||||
interceptor.setFlushMode(HibernateAccessor.FLUSH_AUTO);
|
interceptor.setFlushMode(HibernateAccessor.FLUSH_AUTO);
|
||||||
|
|
||||||
MockServletContext sc = new MockServletContext();
|
expect(sf.openSession()).andReturn(session);
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest(sc);
|
expect(session.getSessionFactory()).andReturn(sf);
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
replay(sf);
|
||||||
|
replay(session);
|
||||||
sf.openSession();
|
interceptor.preHandle(this.webRequest);
|
||||||
sfControl.setReturnValue(session, 1);
|
|
||||||
session.getSessionFactory();
|
|
||||||
sessionControl.setReturnValue(sf);
|
|
||||||
sfControl.replay();
|
|
||||||
sessionControl.replay();
|
|
||||||
interceptor.preHandle(new ServletWebRequest(request));
|
|
||||||
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||||
sfControl.verify();
|
verify(sf);
|
||||||
sessionControl.verify();
|
verify(session);
|
||||||
|
|
||||||
sfControl.reset();
|
reset(sf);
|
||||||
sessionControl.reset();
|
reset(session);
|
||||||
session.flush();
|
session.flush();
|
||||||
sessionControl.setVoidCallable(1);
|
replay(sf);
|
||||||
sfControl.replay();
|
replay(session);
|
||||||
sessionControl.replay();
|
interceptor.postHandle(this.webRequest, null);
|
||||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
|
||||||
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||||
sfControl.verify();
|
verify(sf);
|
||||||
sessionControl.verify();
|
verify(session);
|
||||||
|
|
||||||
sfControl.reset();
|
reset(sf);
|
||||||
sessionControl.reset();
|
reset(session);
|
||||||
session.close();
|
expect(session.close()).andReturn(null);
|
||||||
sessionControl.setReturnValue(null, 1);
|
replay(sf);
|
||||||
sfControl.replay();
|
replay(session);
|
||||||
sessionControl.replay();
|
interceptor.afterCompletion(this.webRequest, null);
|
||||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
|
||||||
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
||||||
sfControl.verify();
|
verify(sf);
|
||||||
sessionControl.verify();
|
verify(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testOpenSessionInViewInterceptorAndDeferredClose() throws Exception {
|
public void testOpenSessionInViewInterceptorAndDeferredClose() throws Exception {
|
||||||
MockControl sfControl = MockControl.createControl(SessionFactory.class);
|
SessionFactory sf = createStrictMock(SessionFactory.class);
|
||||||
final SessionFactory sf = (SessionFactory) sfControl.getMock();
|
Session session = createStrictMock(Session.class);
|
||||||
MockControl sessionControl = MockControl.createControl(Session.class);
|
|
||||||
Session session = (Session) sessionControl.getMock();
|
|
||||||
|
|
||||||
OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor();
|
OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor();
|
||||||
interceptor.setSessionFactory(sf);
|
interceptor.setSessionFactory(sf);
|
||||||
interceptor.setSingleSession(false);
|
interceptor.setSingleSession(false);
|
||||||
|
|
||||||
MockServletContext sc = new MockServletContext();
|
expect(sf.openSession()).andReturn(session);
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest(sc);
|
expect(session.getSessionFactory()).andReturn(sf);
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
|
||||||
|
|
||||||
sf.openSession();
|
|
||||||
sfControl.setReturnValue(session, 1);
|
|
||||||
session.getSessionFactory();
|
|
||||||
sessionControl.setReturnValue(sf, 1);
|
|
||||||
session.setFlushMode(FlushMode.MANUAL);
|
session.setFlushMode(FlushMode.MANUAL);
|
||||||
sessionControl.setVoidCallable(1);
|
replay(sf);
|
||||||
sfControl.replay();
|
replay(session);
|
||||||
sessionControl.replay();
|
|
||||||
|
|
||||||
interceptor.preHandle(new ServletWebRequest(request));
|
interceptor.preHandle(this.webRequest);
|
||||||
org.hibernate.Session sess = SessionFactoryUtils.getSession(sf, true);
|
org.hibernate.Session sess = SessionFactoryUtils.getSession(sf, true);
|
||||||
SessionFactoryUtils.releaseSession(sess, sf);
|
SessionFactoryUtils.releaseSession(sess, sf);
|
||||||
|
|
||||||
// check that further invocations simply participate
|
// check that further invocations simply participate
|
||||||
interceptor.preHandle(new ServletWebRequest(request));
|
interceptor.preHandle(this.webRequest);
|
||||||
|
|
||||||
interceptor.preHandle(new ServletWebRequest(request));
|
interceptor.preHandle(this.webRequest);
|
||||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
interceptor.postHandle(this.webRequest, null);
|
||||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
interceptor.afterCompletion(this.webRequest, null);
|
||||||
|
|
||||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
interceptor.postHandle(this.webRequest, null);
|
||||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
interceptor.afterCompletion(this.webRequest, null);
|
||||||
|
|
||||||
interceptor.preHandle(new ServletWebRequest(request));
|
interceptor.preHandle(this.webRequest);
|
||||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
interceptor.postHandle(this.webRequest, null);
|
||||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
interceptor.afterCompletion(this.webRequest, null);
|
||||||
|
|
||||||
sfControl.verify();
|
verify(sf);
|
||||||
sessionControl.verify();
|
verify(session);
|
||||||
sfControl.reset();
|
|
||||||
sessionControl.reset();
|
|
||||||
|
|
||||||
session.close();
|
reset(sf);
|
||||||
sessionControl.setReturnValue(null, 1);
|
reset(session);
|
||||||
sfControl.replay();
|
expect(session.close()).andReturn(null);
|
||||||
sessionControl.replay();
|
replay(sf);
|
||||||
|
replay(session);
|
||||||
|
|
||||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
interceptor.postHandle(this.webRequest, null);
|
||||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
interceptor.afterCompletion(this.webRequest, null);
|
||||||
sfControl.verify();
|
|
||||||
sessionControl.verify();
|
verify(sf);
|
||||||
|
verify(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testOpenSessionInViewFilterWithSingleSession() throws Exception {
|
public void testOpenSessionInViewFilterWithSingleSession() throws Exception {
|
||||||
MockControl sfControl = MockControl.createControl(SessionFactory.class);
|
final SessionFactory sf = createStrictMock(SessionFactory.class);
|
||||||
final SessionFactory sf = (SessionFactory) sfControl.getMock();
|
Session session = createStrictMock(Session.class);
|
||||||
MockControl sessionControl = MockControl.createControl(Session.class);
|
|
||||||
Session session = (Session) sessionControl.getMock();
|
|
||||||
|
|
||||||
sf.openSession();
|
expect(sf.openSession()).andReturn(session);
|
||||||
sfControl.setReturnValue(session, 1);
|
expect(session.getSessionFactory()).andReturn(sf);
|
||||||
session.getSessionFactory();
|
|
||||||
sessionControl.setReturnValue(sf);
|
|
||||||
session.setFlushMode(FlushMode.MANUAL);
|
session.setFlushMode(FlushMode.MANUAL);
|
||||||
sessionControl.setVoidCallable(1);
|
expect(session.close()).andReturn(null);
|
||||||
session.close();
|
replay(sf);
|
||||||
sessionControl.setReturnValue(null, 1);
|
replay(session);
|
||||||
sfControl.replay();
|
|
||||||
sessionControl.replay();
|
|
||||||
|
|
||||||
MockControl sf2Control = MockControl.createControl(SessionFactory.class);
|
final SessionFactory sf2 = createStrictMock(SessionFactory.class);
|
||||||
final SessionFactory sf2 = (SessionFactory) sf2Control.getMock();
|
Session session2 = createStrictMock(Session.class);
|
||||||
MockControl session2Control = MockControl.createControl(Session.class);
|
|
||||||
Session session2 = (Session) session2Control.getMock();
|
|
||||||
|
|
||||||
sf2.openSession();
|
expect(sf2.openSession()).andReturn(session2);
|
||||||
sf2Control.setReturnValue(session2, 1);
|
expect(session2.getSessionFactory()).andReturn(sf2);
|
||||||
session2.getSessionFactory();
|
|
||||||
session2Control.setReturnValue(sf);
|
|
||||||
session2.setFlushMode(FlushMode.AUTO);
|
session2.setFlushMode(FlushMode.AUTO);
|
||||||
session2Control.setVoidCallable(1);
|
expect(session2.close()).andReturn(null);
|
||||||
session2.close();
|
replay(sf2);
|
||||||
session2Control.setReturnValue(null, 1);
|
replay(session2);
|
||||||
sf2Control.replay();
|
|
||||||
session2Control.replay();
|
|
||||||
|
|
||||||
MockServletContext sc = new MockServletContext();
|
|
||||||
StaticWebApplicationContext wac = new StaticWebApplicationContext();
|
StaticWebApplicationContext wac = new StaticWebApplicationContext();
|
||||||
wac.setServletContext(sc);
|
wac.setServletContext(sc);
|
||||||
wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf);
|
wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf);
|
||||||
wac.getDefaultListableBeanFactory().registerSingleton("mySessionFactory", sf2);
|
wac.getDefaultListableBeanFactory().registerSingleton("mySessionFactory", sf2);
|
||||||
wac.refresh();
|
wac.refresh();
|
||||||
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
|
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest(sc);
|
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
|
||||||
|
|
||||||
MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter");
|
MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter");
|
||||||
MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2");
|
MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2");
|
||||||
|
|
@ -378,44 +424,112 @@ public class OpenSessionInViewTests extends TestCase {
|
||||||
|
|
||||||
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
||||||
assertFalse(TransactionSynchronizationManager.hasResource(sf2));
|
assertFalse(TransactionSynchronizationManager.hasResource(sf2));
|
||||||
filter2.doFilter(request, response, filterChain3);
|
filter2.doFilter(this.request, this.response, filterChain3);
|
||||||
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
||||||
assertFalse(TransactionSynchronizationManager.hasResource(sf2));
|
assertFalse(TransactionSynchronizationManager.hasResource(sf2));
|
||||||
assertNotNull(request.getAttribute("invoked"));
|
assertNotNull(this.request.getAttribute("invoked"));
|
||||||
|
|
||||||
sfControl.verify();
|
verify(sf);
|
||||||
sessionControl.verify();
|
verify(session);
|
||||||
sf2Control.verify();
|
verify(sf2);
|
||||||
session2Control.verify();
|
verify(session2);
|
||||||
|
|
||||||
wac.close();
|
wac.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testOpenSessionInViewFilterWithSingleSessionAndPreBoundSession() throws Exception {
|
@Test
|
||||||
MockControl sfControl = MockControl.createControl(SessionFactory.class);
|
public void testOpenSessionInViewFilterWithSingleSessionAsyncScenario() throws Exception {
|
||||||
final SessionFactory sf = (SessionFactory) sfControl.getMock();
|
final SessionFactory sf = createStrictMock(SessionFactory.class);
|
||||||
MockControl sessionControl = MockControl.createControl(Session.class);
|
Session session = createStrictMock(Session.class);
|
||||||
Session session = (Session) sessionControl.getMock();
|
|
||||||
|
|
||||||
sf.openSession();
|
expect(sf.openSession()).andReturn(session);
|
||||||
sfControl.setReturnValue(session, 1);
|
expect(session.getSessionFactory()).andReturn(sf);
|
||||||
session.getSessionFactory();
|
|
||||||
sessionControl.setReturnValue(sf);
|
|
||||||
session.setFlushMode(FlushMode.MANUAL);
|
session.setFlushMode(FlushMode.MANUAL);
|
||||||
sessionControl.setVoidCallable(1);
|
replay(sf);
|
||||||
session.close();
|
replay(session);
|
||||||
sessionControl.setReturnValue(null, 1);
|
|
||||||
sfControl.replay();
|
StaticWebApplicationContext wac = new StaticWebApplicationContext();
|
||||||
sessionControl.replay();
|
wac.setServletContext(sc);
|
||||||
|
wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf);
|
||||||
|
wac.refresh();
|
||||||
|
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
|
||||||
|
|
||||||
|
MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter");
|
||||||
|
|
||||||
|
final OpenSessionInViewFilter filter = new OpenSessionInViewFilter();
|
||||||
|
filter.init(filterConfig);
|
||||||
|
|
||||||
|
final FilterChain filterChain = new FilterChain() {
|
||||||
|
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) {
|
||||||
|
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||||
|
servletRequest.setAttribute("invoked", Boolean.TRUE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AsyncWebRequest asyncWebRequest = createStrictMock(AsyncWebRequest.class);
|
||||||
|
expect(asyncWebRequest.isAsyncStarted()).andReturn(true);
|
||||||
|
expect(asyncWebRequest.isAsyncStarted()).andReturn(true);
|
||||||
|
replay(asyncWebRequest);
|
||||||
|
|
||||||
|
AsyncExecutionChain chain = AsyncExecutionChain.getForCurrentRequest(this.request);
|
||||||
|
chain.setAsyncWebRequest(asyncWebRequest);
|
||||||
|
|
||||||
|
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
||||||
|
filter.doFilter(this.request, this.response, filterChain);
|
||||||
|
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
||||||
|
assertNotNull(this.request.getAttribute("invoked"));
|
||||||
|
|
||||||
|
verify(sf);
|
||||||
|
verify(session);
|
||||||
|
verify(asyncWebRequest);
|
||||||
|
|
||||||
|
chain.setTaskExecutor(new SyncTaskExecutor());
|
||||||
|
chain.setCallable(new Callable<Object>() {
|
||||||
|
public Object call() {
|
||||||
|
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
reset(asyncWebRequest);
|
||||||
|
asyncWebRequest.startAsync();
|
||||||
|
expect(asyncWebRequest.isAsyncCompleted()).andReturn(false);
|
||||||
|
asyncWebRequest.complete();
|
||||||
|
replay(asyncWebRequest);
|
||||||
|
|
||||||
|
reset(sf);
|
||||||
|
reset(session);
|
||||||
|
expect(session.close()).andReturn(null);
|
||||||
|
replay(sf);
|
||||||
|
replay(session);
|
||||||
|
|
||||||
|
chain.startCallableChainProcessing();
|
||||||
|
assertFalse(TransactionSynchronizationManager.hasResource(sf));
|
||||||
|
|
||||||
|
verify(sf);
|
||||||
|
verify(session);
|
||||||
|
verify(asyncWebRequest);
|
||||||
|
|
||||||
|
wac.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOpenSessionInViewFilterWithSingleSessionAndPreBoundSession() throws Exception {
|
||||||
|
final SessionFactory sf = createStrictMock(SessionFactory.class);
|
||||||
|
Session session = createStrictMock(Session.class);
|
||||||
|
|
||||||
|
expect(sf.openSession()).andReturn(session);
|
||||||
|
expect(session.getSessionFactory()).andReturn(sf);
|
||||||
|
session.setFlushMode(FlushMode.MANUAL);
|
||||||
|
expect(session.close()).andReturn(null);
|
||||||
|
replay(sf);
|
||||||
|
replay(session);
|
||||||
|
|
||||||
MockServletContext sc = new MockServletContext();
|
|
||||||
StaticWebApplicationContext wac = new StaticWebApplicationContext();
|
StaticWebApplicationContext wac = new StaticWebApplicationContext();
|
||||||
wac.setServletContext(sc);
|
wac.setServletContext(sc);
|
||||||
wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf);
|
wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf);
|
||||||
wac.refresh();
|
wac.refresh();
|
||||||
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
|
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest(sc);
|
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
|
||||||
|
|
||||||
MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter");
|
MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter");
|
||||||
MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2");
|
MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2");
|
||||||
|
|
@ -424,7 +538,7 @@ public class OpenSessionInViewTests extends TestCase {
|
||||||
OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor();
|
OpenSessionInViewInterceptor interceptor = new OpenSessionInViewInterceptor();
|
||||||
interceptor.setSessionFactory(sf);
|
interceptor.setSessionFactory(sf);
|
||||||
|
|
||||||
interceptor.preHandle(new ServletWebRequest(request));
|
interceptor.preHandle(this.webRequest);
|
||||||
|
|
||||||
final OpenSessionInViewFilter filter = new OpenSessionInViewFilter();
|
final OpenSessionInViewFilter filter = new OpenSessionInViewFilter();
|
||||||
filter.init(filterConfig);
|
filter.init(filterConfig);
|
||||||
|
|
@ -437,74 +551,57 @@ public class OpenSessionInViewTests extends TestCase {
|
||||||
};
|
};
|
||||||
|
|
||||||
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||||
filter.doFilter(request, response, filterChain);
|
filter.doFilter(this.request, this.response, filterChain);
|
||||||
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
assertTrue(TransactionSynchronizationManager.hasResource(sf));
|
||||||
assertNotNull(request.getAttribute("invoked"));
|
assertNotNull(this.request.getAttribute("invoked"));
|
||||||
|
|
||||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
interceptor.postHandle(this.webRequest, null);
|
||||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
interceptor.afterCompletion(this.webRequest, null);
|
||||||
|
|
||||||
sfControl.verify();
|
verify(sf);
|
||||||
sessionControl.verify();
|
verify(session);
|
||||||
|
|
||||||
wac.close();
|
wac.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testOpenSessionInViewFilterWithDeferredClose() throws Exception {
|
public void testOpenSessionInViewFilterWithDeferredClose() throws Exception {
|
||||||
MockControl sfControl = MockControl.createControl(SessionFactory.class);
|
final SessionFactory sf = createStrictMock(SessionFactory.class);
|
||||||
final SessionFactory sf = (SessionFactory) sfControl.getMock();
|
final Session session = createStrictMock(Session.class);
|
||||||
final MockControl sessionControl = MockControl.createControl(Session.class);
|
|
||||||
final Session session = (Session) sessionControl.getMock();
|
|
||||||
|
|
||||||
sf.openSession();
|
expect(sf.openSession()).andReturn(session);
|
||||||
sfControl.setReturnValue(session, 1);
|
expect(session.getSessionFactory()).andReturn(sf);
|
||||||
session.getSessionFactory();
|
expect(session.getFlushMode()).andReturn(FlushMode.MANUAL);
|
||||||
sessionControl.setReturnValue(sf);
|
|
||||||
session.getFlushMode();
|
|
||||||
sessionControl.setReturnValue(FlushMode.MANUAL, 1);
|
|
||||||
session.setFlushMode(FlushMode.MANUAL);
|
session.setFlushMode(FlushMode.MANUAL);
|
||||||
sessionControl.setVoidCallable(1);
|
replay(sf);
|
||||||
sfControl.replay();
|
replay(session);
|
||||||
sessionControl.replay();
|
|
||||||
|
|
||||||
MockControl sf2Control = MockControl.createControl(SessionFactory.class);
|
final SessionFactory sf2 = createStrictMock(SessionFactory.class);
|
||||||
final SessionFactory sf2 = (SessionFactory) sf2Control.getMock();
|
final Session session2 = createStrictMock(Session.class);
|
||||||
final MockControl session2Control = MockControl.createControl(Session.class);
|
|
||||||
final Session session2 = (Session) session2Control.getMock();
|
|
||||||
MockControl txControl = MockControl.createControl(Transaction.class);
|
|
||||||
Transaction tx = (Transaction) txControl.getMock();
|
|
||||||
MockControl conControl = MockControl.createControl(Connection.class);
|
|
||||||
Connection con = (Connection) conControl.getMock();
|
|
||||||
|
|
||||||
sf2.openSession();
|
Transaction tx = createStrictMock(Transaction.class);
|
||||||
sf2Control.setReturnValue(session2, 1);
|
Connection con = createStrictMock(Connection.class);
|
||||||
session2.beginTransaction();
|
|
||||||
session2Control.setReturnValue(tx, 1);
|
expect(sf2.openSession()).andReturn(session2);
|
||||||
session2.connection();
|
expect(session2.connection()).andReturn(con);
|
||||||
session2Control.setReturnValue(con, 2);
|
expect(session2.beginTransaction()).andReturn(tx);
|
||||||
|
expect(session2.isConnected()).andReturn(true);
|
||||||
|
expect(session2.connection()).andReturn(con);
|
||||||
tx.commit();
|
tx.commit();
|
||||||
txControl.setVoidCallable(1);
|
expect(con.isReadOnly()).andReturn(false);
|
||||||
session2.isConnected();
|
|
||||||
session2Control.setReturnValue(true, 1);
|
|
||||||
con.isReadOnly();
|
|
||||||
conControl.setReturnValue(false, 1);
|
|
||||||
session2.setFlushMode(FlushMode.MANUAL);
|
session2.setFlushMode(FlushMode.MANUAL);
|
||||||
session2Control.setVoidCallable(1);
|
|
||||||
|
|
||||||
sf2Control.replay();
|
replay(sf2);
|
||||||
session2Control.replay();
|
replay(session2);
|
||||||
txControl.replay();
|
replay(tx);
|
||||||
conControl.replay();
|
replay(con);
|
||||||
|
|
||||||
MockServletContext sc = new MockServletContext();
|
|
||||||
StaticWebApplicationContext wac = new StaticWebApplicationContext();
|
StaticWebApplicationContext wac = new StaticWebApplicationContext();
|
||||||
wac.setServletContext(sc);
|
wac.setServletContext(sc);
|
||||||
wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf);
|
wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf);
|
||||||
wac.getDefaultListableBeanFactory().registerSingleton("mySessionFactory", sf2);
|
wac.getDefaultListableBeanFactory().registerSingleton("mySessionFactory", sf2);
|
||||||
wac.refresh();
|
wac.refresh();
|
||||||
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
|
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest(sc);
|
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
|
||||||
|
|
||||||
MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter");
|
MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter");
|
||||||
MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2");
|
MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2");
|
||||||
|
|
@ -526,12 +623,11 @@ public class OpenSessionInViewTests extends TestCase {
|
||||||
SessionFactoryUtils.releaseSession(sess, sf);
|
SessionFactoryUtils.releaseSession(sess, sf);
|
||||||
tm.commit(ts);
|
tm.commit(ts);
|
||||||
|
|
||||||
sessionControl.verify();
|
verify(session);
|
||||||
sessionControl.reset();
|
reset(session);
|
||||||
|
|
||||||
session.close();
|
expect(session.close()).andReturn(null);
|
||||||
sessionControl.setReturnValue(null, 1);
|
replay(session);
|
||||||
sessionControl.replay();
|
|
||||||
|
|
||||||
servletRequest.setAttribute("invoked", Boolean.TRUE);
|
servletRequest.setAttribute("invoked", Boolean.TRUE);
|
||||||
}
|
}
|
||||||
|
|
@ -545,12 +641,11 @@ public class OpenSessionInViewTests extends TestCase {
|
||||||
TransactionStatus ts = tm.getTransaction(new DefaultTransactionDefinition());
|
TransactionStatus ts = tm.getTransaction(new DefaultTransactionDefinition());
|
||||||
tm.commit(ts);
|
tm.commit(ts);
|
||||||
|
|
||||||
session2Control.verify();
|
verify(session2);
|
||||||
session2Control.reset();
|
reset(session2);
|
||||||
|
|
||||||
session2.close();
|
expect(session2.close()).andReturn(null);
|
||||||
session2Control.setReturnValue(null, 1);
|
replay(session2);
|
||||||
session2Control.replay();
|
|
||||||
|
|
||||||
filter.doFilter(servletRequest, servletResponse, filterChain);
|
filter.doFilter(servletRequest, servletResponse, filterChain);
|
||||||
}
|
}
|
||||||
|
|
@ -558,44 +653,48 @@ public class OpenSessionInViewTests extends TestCase {
|
||||||
|
|
||||||
FilterChain filterChain3 = new PassThroughFilterChain(filter2, filterChain2);
|
FilterChain filterChain3 = new PassThroughFilterChain(filter2, filterChain2);
|
||||||
|
|
||||||
filter2.doFilter(request, response, filterChain3);
|
filter2.doFilter(this.request, this.response, filterChain3);
|
||||||
assertNotNull(request.getAttribute("invoked"));
|
assertNotNull(this.request.getAttribute("invoked"));
|
||||||
|
|
||||||
sfControl.verify();
|
verify(sf);
|
||||||
sessionControl.verify();
|
verify(session);
|
||||||
sf2Control.verify();
|
|
||||||
session2Control.verify();
|
verify(sf2);
|
||||||
txControl.verify();
|
verify(session2);
|
||||||
conControl.verify();
|
verify(tx);
|
||||||
|
verify(con);
|
||||||
|
|
||||||
wac.close();
|
wac.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testOpenSessionInViewFilterWithDeferredCloseAndAlreadyActiveDeferredClose() throws Exception {
|
public void testOpenSessionInViewFilterWithDeferredCloseAndAlreadyActiveDeferredClose() throws Exception {
|
||||||
MockControl sfControl = MockControl.createControl(SessionFactory.class);
|
final SessionFactory sf = createStrictMock(SessionFactory.class);
|
||||||
final SessionFactory sf = (SessionFactory) sfControl.getMock();
|
final Session session = createStrictMock(Session.class);
|
||||||
final MockControl sessionControl = MockControl.createControl(Session.class);
|
|
||||||
final Session session = (Session) sessionControl.getMock();
|
|
||||||
|
|
||||||
sf.openSession();
|
expect(sf.openSession()).andReturn(session);
|
||||||
sfControl.setReturnValue(session, 1);
|
expect(session.getSessionFactory()).andReturn(sf);
|
||||||
session.getSessionFactory();
|
expect(session.getFlushMode()).andReturn(FlushMode.MANUAL);
|
||||||
sessionControl.setReturnValue(sf);
|
|
||||||
session.getFlushMode();
|
|
||||||
sessionControl.setReturnValue(FlushMode.MANUAL, 1);
|
|
||||||
session.setFlushMode(FlushMode.MANUAL);
|
session.setFlushMode(FlushMode.MANUAL);
|
||||||
sessionControl.setVoidCallable(1);
|
replay(sf);
|
||||||
sfControl.replay();
|
replay(session);
|
||||||
sessionControl.replay();
|
|
||||||
|
// sf.openSession();
|
||||||
|
// sfControl.setReturnValue(session, 1);
|
||||||
|
// session.getSessionFactory();
|
||||||
|
// sessionControl.setReturnValue(sf);
|
||||||
|
// session.getFlushMode();
|
||||||
|
// sessionControl.setReturnValue(FlushMode.MANUAL, 1);
|
||||||
|
// session.setFlushMode(FlushMode.MANUAL);
|
||||||
|
// sessionControl.setVoidCallable(1);
|
||||||
|
// sfControl.replay();
|
||||||
|
// sessionControl.replay();
|
||||||
|
|
||||||
MockServletContext sc = new MockServletContext();
|
|
||||||
StaticWebApplicationContext wac = new StaticWebApplicationContext();
|
StaticWebApplicationContext wac = new StaticWebApplicationContext();
|
||||||
wac.setServletContext(sc);
|
wac.setServletContext(sc);
|
||||||
wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf);
|
wac.getDefaultListableBeanFactory().registerSingleton("sessionFactory", sf);
|
||||||
wac.refresh();
|
wac.refresh();
|
||||||
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
|
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest(sc);
|
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
|
||||||
|
|
||||||
MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter");
|
MockFilterConfig filterConfig = new MockFilterConfig(wac.getServletContext(), "filter");
|
||||||
MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2");
|
MockFilterConfig filterConfig2 = new MockFilterConfig(wac.getServletContext(), "filter2");
|
||||||
|
|
@ -607,7 +706,7 @@ public class OpenSessionInViewTests extends TestCase {
|
||||||
interceptor.setSessionFactory(sf);
|
interceptor.setSessionFactory(sf);
|
||||||
interceptor.setSingleSession(false);
|
interceptor.setSingleSession(false);
|
||||||
|
|
||||||
interceptor.preHandle(new ServletWebRequest(request));
|
interceptor.preHandle(webRequest);
|
||||||
|
|
||||||
final OpenSessionInViewFilter filter = new OpenSessionInViewFilter();
|
final OpenSessionInViewFilter filter = new OpenSessionInViewFilter();
|
||||||
filter.init(filterConfig);
|
filter.init(filterConfig);
|
||||||
|
|
@ -623,15 +722,14 @@ public class OpenSessionInViewTests extends TestCase {
|
||||||
SessionFactoryUtils.releaseSession(sess, sf);
|
SessionFactoryUtils.releaseSession(sess, sf);
|
||||||
tm.commit(ts);
|
tm.commit(ts);
|
||||||
|
|
||||||
sessionControl.verify();
|
verify(session);
|
||||||
sessionControl.reset();
|
reset(session);
|
||||||
try {
|
try {
|
||||||
session.close();
|
expect(session.close()).andReturn(null);
|
||||||
}
|
}
|
||||||
catch (HibernateException ex) {
|
catch (HibernateException ex) {
|
||||||
}
|
}
|
||||||
sessionControl.setReturnValue(null, 1);
|
replay(session);
|
||||||
sessionControl.replay();
|
|
||||||
|
|
||||||
servletRequest.setAttribute("invoked", Boolean.TRUE);
|
servletRequest.setAttribute("invoked", Boolean.TRUE);
|
||||||
}
|
}
|
||||||
|
|
@ -644,16 +742,25 @@ public class OpenSessionInViewTests extends TestCase {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
filter.doFilter(request, response, filterChain2);
|
filter.doFilter(this.request, this.response, filterChain2);
|
||||||
assertNotNull(request.getAttribute("invoked"));
|
assertNotNull(this.request.getAttribute("invoked"));
|
||||||
|
|
||||||
interceptor.postHandle(new ServletWebRequest(request), null);
|
interceptor.postHandle(webRequest, null);
|
||||||
interceptor.afterCompletion(new ServletWebRequest(request), null);
|
interceptor.afterCompletion(webRequest, null);
|
||||||
|
|
||||||
sfControl.verify();
|
verify(sf);
|
||||||
sessionControl.verify();
|
verify(session);
|
||||||
|
|
||||||
wac.close();
|
wac.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
private static class SyncTaskExecutor extends SimpleAsyncTaskExecutor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Runnable task, long startTimeout) {
|
||||||
|
task.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ import javax.servlet.ServletRequest;
|
||||||
import org.springframework.core.task.AsyncTaskExecutor;
|
import org.springframework.core.task.AsyncTaskExecutor;
|
||||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.web.context.request.RequestAttributes;
|
||||||
|
import org.springframework.web.context.request.WebRequest;
|
||||||
import org.springframework.web.context.request.async.DeferredResult.DeferredResultHandler;
|
import org.springframework.web.context.request.async.DeferredResult.DeferredResultHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -77,6 +79,20 @@ public final class AsyncExecutionChain {
|
||||||
return chain;
|
return chain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain the AsyncExecutionChain for the current request.
|
||||||
|
* Or if not found, create an instance and associate it with the request.
|
||||||
|
*/
|
||||||
|
public static AsyncExecutionChain getForCurrentRequest(WebRequest request) {
|
||||||
|
int scope = RequestAttributes.SCOPE_REQUEST;
|
||||||
|
AsyncExecutionChain chain = (AsyncExecutionChain) request.getAttribute(CALLABLE_CHAIN_ATTRIBUTE, scope);
|
||||||
|
if (chain == null) {
|
||||||
|
chain = new AsyncExecutionChain();
|
||||||
|
request.setAttribute(CALLABLE_CHAIN_ATTRIBUTE, chain, scope);
|
||||||
|
}
|
||||||
|
return chain;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide an instance of an AsyncWebRequest.
|
* Provide an instance of an AsyncWebRequest.
|
||||||
* This property must be set before async request processing can begin.
|
* This property must be set before async request processing can begin.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2012 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.web.context.request.async;
|
||||||
|
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
|
import org.springframework.web.context.request.WebRequest;
|
||||||
|
import org.springframework.web.context.request.WebRequestInterceptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends {@link WebRequestInterceptor} with lifecycle methods specific to async
|
||||||
|
* request processing.
|
||||||
|
*
|
||||||
|
* <p>This is the sequence of events on the main thread in an async scenario:
|
||||||
|
* <ol>
|
||||||
|
* <li>{@link #preHandle(WebRequest)}
|
||||||
|
* <li>{@link #getAsyncCallable(WebRequest)}
|
||||||
|
* <li>... <em>handler execution</em>
|
||||||
|
* <li>{@link #postHandleAsyncStarted(WebRequest)}
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* <p>This is the sequence of events on the async thread:
|
||||||
|
* <ol>
|
||||||
|
* <li>Async {@link Callable#call()} (the {@code Callable} returned by {@code getAsyncCallable})
|
||||||
|
* <li>... <em>async handler execution</em>
|
||||||
|
* <li>{@link #postHandle(WebRequest, org.springframework.ui.ModelMap)}
|
||||||
|
* <li>{@link #afterCompletion(WebRequest, Exception)}
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* @author Rossen Stoyanchev
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
public interface AsyncWebRequestInterceptor extends WebRequestInterceptor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked <em>after</em> {@link #preHandle(WebRequest)} and <em>before</em>
|
||||||
|
* the handler is executed. The returned {@link Callable} is used only if
|
||||||
|
* handler execution leads to teh start of async processing. It is invoked
|
||||||
|
* the async thread before the request is handled fro.
|
||||||
|
* <p>Implementations can use this <code>Callable</code> to initialize
|
||||||
|
* ThreadLocal attributes on the async thread.
|
||||||
|
* @return a {@link Callable} instance or <code>null</code>
|
||||||
|
*/
|
||||||
|
AbstractDelegatingCallable getAsyncCallable(WebRequest request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked <em>after</em> the execution of a handler if the handler started
|
||||||
|
* async processing instead of handling the request. Effectively this method
|
||||||
|
* is invoked on the way out of the main processing thread instead of
|
||||||
|
* {@link #postHandle(WebRequest, org.springframework.ui.ModelMap)}. The
|
||||||
|
* <code>postHandle</code> method is invoked after the request is handled
|
||||||
|
* in the async thread.
|
||||||
|
* <p>Implementations of this method can ensure ThreadLocal attributes bound
|
||||||
|
* to the main thread are cleared and also prepare for binding them to the
|
||||||
|
* async thread.
|
||||||
|
*/
|
||||||
|
void postHandleAsyncStarted(WebRequest request);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2012 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.web.servlet;
|
||||||
|
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.springframework.web.context.request.WebRequest;
|
||||||
|
import org.springframework.web.context.request.async.AbstractDelegatingCallable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends {@link HanderInterceptor} with lifecycle methods specific to async
|
||||||
|
* request processing.
|
||||||
|
*
|
||||||
|
* <p>This is the sequence of events on the main thread in an async scenario:
|
||||||
|
* <ol>
|
||||||
|
* <li>{@link #preHandle(WebRequest)}
|
||||||
|
* <li>{@link #getAsyncCallable(WebRequest)}
|
||||||
|
* <li>... <em>handler execution</em>
|
||||||
|
* <li>{@link #postHandleAsyncStarted(WebRequest)}
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* <p>This is the sequence of events on the async thread:
|
||||||
|
* <ol>
|
||||||
|
* <li>Async {@link Callable#call()} (the {@code Callable} returned by {@code getAsyncCallable})
|
||||||
|
* <li>... <em>async handler execution</em>
|
||||||
|
* <li>{@link #postHandle(WebRequest, org.springframework.ui.ModelMap)}
|
||||||
|
* <li>{@link #afterCompletion(WebRequest, Exception)}
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* @author Rossen Stoyanchev
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
public interface AsyncHandlerInterceptor extends HandlerInterceptor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked <em>after</em> {@link #preHandle(WebRequest)} and <em>before</em>
|
||||||
|
* the handler is executed. The returned {@link Callable} is used only if
|
||||||
|
* handler execution leads to teh start of async processing. It is invoked
|
||||||
|
* the async thread before the request is handled fro.
|
||||||
|
* <p>Implementations can use this <code>Callable</code> to initialize
|
||||||
|
* ThreadLocal attributes on the async thread.
|
||||||
|
* @param request current HTTP request
|
||||||
|
* @param response current HTTP response
|
||||||
|
* @param handler chosen handler to execute, for type and/or instance examination
|
||||||
|
* @return a {@link Callable} instance or <code>null</code>
|
||||||
|
*/
|
||||||
|
AbstractDelegatingCallable getAsyncCallable(HttpServletRequest request, HttpServletResponse response, Object handler);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked <em>after</em> the execution of a handler if the handler started
|
||||||
|
* async processing instead of handling the request. Effectively this method
|
||||||
|
* is invoked on the way out of the main processing thread instead of
|
||||||
|
* {@link #postHandle(WebRequest, org.springframework.ui.ModelMap)}. The
|
||||||
|
* <code>postHandle</code> method is invoked after the request is handled
|
||||||
|
* in the async thread.
|
||||||
|
* <p>Implementations of this method can ensure ThreadLocal attributes bound
|
||||||
|
* to the main thread are cleared and also prepare for binding them to the
|
||||||
|
* async thread.
|
||||||
|
* @param request current HTTP request
|
||||||
|
* @param response current HTTP response
|
||||||
|
* @param handler chosen handler to execute, for type and/or instance examination
|
||||||
|
*/
|
||||||
|
void postHandleAsyncStarted(HttpServletRequest request, HttpServletResponse response, Object handler);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -941,6 +941,8 @@ public class DispatcherServlet extends FrameworkServlet {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mappedHandler.addDelegatingCallables(processedRequest, response);
|
||||||
|
|
||||||
asyncChain.addDelegatingCallable(
|
asyncChain.addDelegatingCallable(
|
||||||
getDispatchAsyncCallable(mappedHandler, request, response, processedRequest));
|
getDispatchAsyncCallable(mappedHandler, request, response, processedRequest));
|
||||||
|
|
||||||
|
|
@ -948,6 +950,7 @@ public class DispatcherServlet extends FrameworkServlet {
|
||||||
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
|
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
|
||||||
|
|
||||||
if (asyncChain.isAsyncStarted()) {
|
if (asyncChain.isAsyncStarted()) {
|
||||||
|
mappedHandler.applyPostHandleAsyncStarted(processedRequest, response);
|
||||||
logger.debug("Exiting request thread and leaving the response open");
|
logger.debug("Exiting request thread and leaving the response open");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
import org.springframework.web.context.request.async.AsyncExecutionChain;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler execution chain, consisting of handler object and any handler interceptors.
|
* Handler execution chain, consisting of handler object and any handler interceptors.
|
||||||
|
|
@ -139,7 +140,7 @@ public class HandlerExecutionChain {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply preHandle methods of registered interceptors.
|
* Apply postHandle methods of registered interceptors.
|
||||||
*/
|
*/
|
||||||
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv)
|
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
@ -153,6 +154,53 @@ public class HandlerExecutionChain {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add delegating, async Callable instances to the {@link AsyncExecutionChain}
|
||||||
|
* for use in case of asynchronous request processing.
|
||||||
|
*/
|
||||||
|
void addDelegatingCallables(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
throws Exception {
|
||||||
|
|
||||||
|
if (getInterceptors() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = getInterceptors().length - 1; i >= 0; i--) {
|
||||||
|
HandlerInterceptor interceptor = getInterceptors()[i];
|
||||||
|
if (interceptor instanceof AsyncHandlerInterceptor) {
|
||||||
|
try {
|
||||||
|
AsyncHandlerInterceptor asyncInterceptor = (AsyncHandlerInterceptor) interceptor;
|
||||||
|
AsyncExecutionChain chain = AsyncExecutionChain.getForCurrentRequest(request);
|
||||||
|
chain.addDelegatingCallable(asyncInterceptor.getAsyncCallable(request, response, this.handler));
|
||||||
|
}
|
||||||
|
catch (Throwable ex) {
|
||||||
|
logger.error("HandlerInterceptor.addAsyncCallables threw exception", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger postHandleAsyncStarted callbacks on the mapped HandlerInterceptors.
|
||||||
|
*/
|
||||||
|
void applyPostHandleAsyncStarted(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
throws Exception {
|
||||||
|
|
||||||
|
if (getInterceptors() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = getInterceptors().length - 1; i >= 0; i--) {
|
||||||
|
HandlerInterceptor interceptor = getInterceptors()[i];
|
||||||
|
if (interceptor instanceof AsyncHandlerInterceptor) {
|
||||||
|
try {
|
||||||
|
((AsyncHandlerInterceptor) interceptor).postHandleAsyncStarted(request, response, this.handler);
|
||||||
|
}
|
||||||
|
catch (Throwable ex) {
|
||||||
|
logger.error("HandlerInterceptor.postHandleAsyncStarted threw exception", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
|
* Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
|
||||||
* Will just invoke afterCompletion for all interceptors whose preHandle invocation
|
* Will just invoke afterCompletion for all interceptors whose preHandle invocation
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,9 @@ import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.web.context.request.WebRequestInterceptor;
|
import org.springframework.web.context.request.WebRequestInterceptor;
|
||||||
import org.springframework.web.servlet.HandlerInterceptor;
|
import org.springframework.web.context.request.async.AbstractDelegatingCallable;
|
||||||
|
import org.springframework.web.context.request.async.AsyncWebRequestInterceptor;
|
||||||
|
import org.springframework.web.servlet.AsyncHandlerInterceptor;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -33,7 +35,7 @@ import org.springframework.web.servlet.ModelAndView;
|
||||||
* @see org.springframework.web.context.request.WebRequestInterceptor
|
* @see org.springframework.web.context.request.WebRequestInterceptor
|
||||||
* @see org.springframework.web.servlet.HandlerInterceptor
|
* @see org.springframework.web.servlet.HandlerInterceptor
|
||||||
*/
|
*/
|
||||||
public class WebRequestHandlerInterceptorAdapter implements HandlerInterceptor {
|
public class WebRequestHandlerInterceptorAdapter implements AsyncHandlerInterceptor {
|
||||||
|
|
||||||
private final WebRequestInterceptor requestInterceptor;
|
private final WebRequestInterceptor requestInterceptor;
|
||||||
|
|
||||||
|
|
@ -55,6 +57,25 @@ public class WebRequestHandlerInterceptorAdapter implements HandlerInterceptor {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AbstractDelegatingCallable getAsyncCallable(HttpServletRequest request,
|
||||||
|
HttpServletResponse response, Object handler) {
|
||||||
|
|
||||||
|
if (this.requestInterceptor instanceof AsyncWebRequestInterceptor) {
|
||||||
|
AsyncWebRequestInterceptor asyncInterceptor = (AsyncWebRequestInterceptor) this.requestInterceptor;
|
||||||
|
DispatcherServletWebRequest webRequest = new DispatcherServletWebRequest(request, response);
|
||||||
|
return asyncInterceptor.getAsyncCallable(webRequest);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postHandleAsyncStarted(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
||||||
|
if (this.requestInterceptor instanceof AsyncWebRequestInterceptor) {
|
||||||
|
AsyncWebRequestInterceptor asyncInterceptor = (AsyncWebRequestInterceptor) this.requestInterceptor;
|
||||||
|
DispatcherServletWebRequest webRequest = new DispatcherServletWebRequest(request, response);
|
||||||
|
asyncInterceptor.postHandleAsyncStarted(webRequest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
|
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
package org.springframework.web.servlet;
|
package org.springframework.web.servlet;
|
||||||
|
|
||||||
import static org.easymock.EasyMock.createMock;
|
import static org.easymock.EasyMock.createStrictMock;
|
||||||
import static org.easymock.EasyMock.expect;
|
import static org.easymock.EasyMock.expect;
|
||||||
import static org.easymock.EasyMock.replay;
|
import static org.easymock.EasyMock.replay;
|
||||||
import static org.easymock.EasyMock.verify;
|
import static org.easymock.EasyMock.verify;
|
||||||
|
|
@ -26,6 +26,7 @@ import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.mock.web.MockHttpServletResponse;
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
|
import org.springframework.web.context.request.async.AbstractDelegatingCallable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A test fixture with HandlerExecutionChain and mock handler interceptors.
|
* A test fixture with HandlerExecutionChain and mock handler interceptors.
|
||||||
|
|
@ -42,11 +43,11 @@ public class HandlerExecutionChainTests {
|
||||||
|
|
||||||
private MockHttpServletResponse response;
|
private MockHttpServletResponse response;
|
||||||
|
|
||||||
private HandlerInterceptor interceptor1;
|
private AsyncHandlerInterceptor interceptor1;
|
||||||
|
|
||||||
private HandlerInterceptor interceptor2;
|
private AsyncHandlerInterceptor interceptor2;
|
||||||
|
|
||||||
private HandlerInterceptor interceptor3;
|
private AsyncHandlerInterceptor interceptor3;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
|
|
@ -56,9 +57,9 @@ public class HandlerExecutionChainTests {
|
||||||
this.handler = new Object();
|
this.handler = new Object();
|
||||||
this.chain = new HandlerExecutionChain(this.handler);
|
this.chain = new HandlerExecutionChain(this.handler);
|
||||||
|
|
||||||
this.interceptor1 = createMock(HandlerInterceptor.class);
|
this.interceptor1 = createStrictMock(AsyncHandlerInterceptor.class);
|
||||||
this.interceptor2 = createMock(HandlerInterceptor.class);
|
this.interceptor2 = createStrictMock(AsyncHandlerInterceptor.class);
|
||||||
this.interceptor3 = createMock(HandlerInterceptor.class);
|
this.interceptor3 = createStrictMock(AsyncHandlerInterceptor.class);
|
||||||
|
|
||||||
this.chain.addInterceptor(this.interceptor1);
|
this.chain.addInterceptor(this.interceptor1);
|
||||||
this.chain.addInterceptor(this.interceptor2);
|
this.chain.addInterceptor(this.interceptor2);
|
||||||
|
|
@ -91,7 +92,42 @@ public class HandlerExecutionChainTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void earlyExit() throws Exception {
|
public void successAsyncScenario() throws Exception {
|
||||||
|
ModelAndView mav = new ModelAndView();
|
||||||
|
|
||||||
|
expect(this.interceptor1.preHandle(this.request, this.response, this.handler)).andReturn(true);
|
||||||
|
expect(this.interceptor2.preHandle(this.request, this.response, this.handler)).andReturn(true);
|
||||||
|
expect(this.interceptor3.preHandle(this.request, this.response, this.handler)).andReturn(true);
|
||||||
|
|
||||||
|
expect(this.interceptor1.getAsyncCallable(request, response, this.handler)).andReturn(new TestAsyncCallable());
|
||||||
|
expect(this.interceptor2.getAsyncCallable(request, response, this.handler)).andReturn(new TestAsyncCallable());
|
||||||
|
expect(this.interceptor3.getAsyncCallable(request, response, this.handler)).andReturn(new TestAsyncCallable());
|
||||||
|
|
||||||
|
this.interceptor1.postHandleAsyncStarted(request, response, this.handler);
|
||||||
|
this.interceptor2.postHandleAsyncStarted(request, response, this.handler);
|
||||||
|
this.interceptor3.postHandleAsyncStarted(request, response, this.handler);
|
||||||
|
|
||||||
|
this.interceptor1.postHandle(this.request, this.response, this.handler, mav);
|
||||||
|
this.interceptor2.postHandle(this.request, this.response, this.handler, mav);
|
||||||
|
this.interceptor3.postHandle(this.request, this.response, this.handler, mav);
|
||||||
|
|
||||||
|
this.interceptor3.afterCompletion(this.request, this.response, this.handler, null);
|
||||||
|
this.interceptor2.afterCompletion(this.request, this.response, this.handler, null);
|
||||||
|
this.interceptor1.afterCompletion(this.request, this.response, this.handler, null);
|
||||||
|
|
||||||
|
replay(this.interceptor1, this.interceptor2, this.interceptor3);
|
||||||
|
|
||||||
|
this.chain.applyPreHandle(request, response);
|
||||||
|
this.chain.addDelegatingCallables(request, response);
|
||||||
|
this.chain.applyPostHandleAsyncStarted(request, response);
|
||||||
|
this.chain.applyPostHandle(request, response, mav);
|
||||||
|
this.chain.triggerAfterCompletion(this.request, this.response, null);
|
||||||
|
|
||||||
|
verify(this.interceptor1, this.interceptor2, this.interceptor3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void earlyExitInPreHandle() throws Exception {
|
||||||
expect(this.interceptor1.preHandle(this.request, this.response, this.handler)).andReturn(true);
|
expect(this.interceptor1.preHandle(this.request, this.response, this.handler)).andReturn(true);
|
||||||
expect(this.interceptor2.preHandle(this.request, this.response, this.handler)).andReturn(false);
|
expect(this.interceptor2.preHandle(this.request, this.response, this.handler)).andReturn(false);
|
||||||
|
|
||||||
|
|
@ -155,4 +191,12 @@ public class HandlerExecutionChainTests {
|
||||||
verify(this.interceptor1, this.interceptor2, this.interceptor3);
|
verify(this.interceptor1, this.interceptor2, this.interceptor3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static class TestAsyncCallable extends AbstractDelegatingCallable {
|
||||||
|
|
||||||
|
public Object call() throws Exception {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue