enhanced conversation persistence context listeners to support conditional "persistenceContext" and "commit" attributes. improved tests.
This commit is contained in:
@@ -62,35 +62,36 @@ public class HibernateSessionPerConversationListener extends FlowExecutionListen
|
||||
}
|
||||
|
||||
public void sessionCreated(RequestContext context, FlowSession session) {
|
||||
if (session.isRoot()) {
|
||||
if (session.isRoot() && session.getDefinition().getAttributes().contains("persistenceContext")) {
|
||||
Session hibernateSession = createSession(context);
|
||||
context.getConversationScope().put(HIBERNATE_SESSION_ATTRIBUTE, hibernateSession);
|
||||
bind(hibernateSession, context);
|
||||
bind(hibernateSession, context, session);
|
||||
}
|
||||
}
|
||||
|
||||
public void resumed(RequestContext context) {
|
||||
Session hibSession = getHibernateSession(context);
|
||||
bind(hibSession, context);
|
||||
bind(getHibernateSession(context), context, context.getFlowExecutionContext().getActiveSession());
|
||||
}
|
||||
|
||||
public void paused(RequestContext context, ViewSelection selectedView) {
|
||||
Session session = getHibernateSession(context);
|
||||
unbind(session, context);
|
||||
unbind(getHibernateSession(context), context, context.getFlowExecutionContext().getActiveSession());
|
||||
}
|
||||
|
||||
public void sessionEnded(RequestContext context, FlowSession session, AttributeMap output) {
|
||||
if (session.isRoot()) {
|
||||
Session hibernateSession = (Session) context.getConversationScope().remove(HIBERNATE_SESSION_ATTRIBUTE);
|
||||
hibernateSession.flush();
|
||||
unbind(hibernateSession, context);
|
||||
hibernateSession.close();
|
||||
Boolean commitStatus = session.getState().getAttributes().getBoolean("commit");
|
||||
if (commitStatus == null || commitStatus.equals(Boolean.TRUE)) {
|
||||
// assume a commit by default and when 'commit' attribute = true
|
||||
hibernateSession.flush();
|
||||
hibernateSession.close();
|
||||
}
|
||||
unbind(hibernateSession, context, session);
|
||||
}
|
||||
}
|
||||
|
||||
public void exceptionThrown(RequestContext context, FlowExecutionException exception) {
|
||||
Session session = getHibernateSession(context);
|
||||
unbind(session, context);
|
||||
unbind(getHibernateSession(context), context, context.getFlowExecutionContext().getActiveSession());
|
||||
}
|
||||
|
||||
// internal helpers
|
||||
@@ -105,18 +106,18 @@ public class HibernateSessionPerConversationListener extends FlowExecutionListen
|
||||
return (Session) context.getConversationScope().get(HIBERNATE_SESSION_ATTRIBUTE);
|
||||
}
|
||||
|
||||
private void bind(Session hibSession, RequestContext context) {
|
||||
SessionHolder sessionHolder = new SessionHolder(hibSession);
|
||||
if (context.getActiveFlow().getAttributes().getBoolean("transactional").booleanValue() == true) {
|
||||
Transaction tx = hibSession.beginTransaction();
|
||||
private void bind(Session session, RequestContext context, FlowSession flowSession) {
|
||||
SessionHolder sessionHolder = new SessionHolder(session);
|
||||
if (flowSession.getDefinition().getAttributes().contains("transactional")) {
|
||||
Transaction tx = session.beginTransaction();
|
||||
sessionHolder.setTransaction(tx);
|
||||
}
|
||||
TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
|
||||
}
|
||||
|
||||
private void unbind(Session hibSession, RequestContext context) {
|
||||
if (context.getActiveFlow().getAttributes().getBoolean("transactional").booleanValue() == true) {
|
||||
hibSession.getTransaction().commit();
|
||||
private void unbind(Session session, RequestContext context, FlowSession flowSession) {
|
||||
if (flowSession.getDefinition().getAttributes().contains("transactional")) {
|
||||
session.getTransaction().commit();
|
||||
}
|
||||
TransactionSynchronizationManager.unbindResource(sessionFactory);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,9 @@ import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
||||
import org.springframework.orm.hibernate3.HibernateCallback;
|
||||
import org.springframework.orm.hibernate3.HibernateTemplate;
|
||||
import org.springframework.orm.hibernate3.LocalSessionFactoryBean;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.webflow.engine.EndState;
|
||||
import org.springframework.webflow.execution.FlowExecutionException;
|
||||
import org.springframework.webflow.execution.ViewSelection;
|
||||
import org.springframework.webflow.test.MockFlowSession;
|
||||
import org.springframework.webflow.test.MockRequestContext;
|
||||
@@ -42,114 +45,188 @@ import org.springframework.webflow.test.MockRequestContext;
|
||||
* @author Ben Hale
|
||||
*/
|
||||
public class HibernateSessionPerConversationListenerTests extends TestCase {
|
||||
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
private HibernateTemplate hibernateTemplate;
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
private HibernateSessionPerConversationListener listener;
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
DataSource dataSource = getDataSource();
|
||||
populateDataBase(dataSource);
|
||||
jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
SessionFactory sessionFactory = getSessionFactory(dataSource);
|
||||
hibernateTemplate = new HibernateTemplate(sessionFactory);
|
||||
hibernateTemplate.setCheckWriteOperations(false);
|
||||
listener = new HibernateSessionPerConversationListener(sessionFactory);
|
||||
}
|
||||
private HibernateTemplate hibernateTemplate;
|
||||
|
||||
public void testSameSession() {
|
||||
MockRequestContext context = new MockRequestContext();
|
||||
MockFlowSession flowSession = new MockFlowSession();
|
||||
listener.sessionCreated(context, flowSession);
|
||||
private HibernateSessionPerConversationListener listener;
|
||||
|
||||
// Session created and bound to conversation
|
||||
final Session hibSession = (Session) context.getConversationScope().get("hibernate.session");
|
||||
assertNotNull("Should have been populated", hibSession);
|
||||
listener.paused(context, ViewSelection.NULL_VIEW);
|
||||
protected void setUp() throws Exception {
|
||||
DataSource dataSource = getDataSource();
|
||||
populateDataBase(dataSource);
|
||||
jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
sessionFactory = getSessionFactory(dataSource);
|
||||
hibernateTemplate = new HibernateTemplate(sessionFactory);
|
||||
hibernateTemplate.setCheckWriteOperations(false);
|
||||
listener = new HibernateSessionPerConversationListener(sessionFactory);
|
||||
}
|
||||
|
||||
// Session bound to thread local variable
|
||||
listener.resumed(context);
|
||||
hibernateTemplate.execute(new HibernateCallback() {
|
||||
public Object doInHibernate(Session session) throws HibernateException, SQLException {
|
||||
assertSame("Should have been original instance", hibSession, session);
|
||||
return null;
|
||||
}
|
||||
}, true);
|
||||
listener.paused(context, ViewSelection.NULL_VIEW);
|
||||
}
|
||||
public void testSameSession() {
|
||||
MockRequestContext context = new MockRequestContext();
|
||||
MockFlowSession flowSession = new MockFlowSession();
|
||||
flowSession.getDefinitionInternal().getAttributeMap().put("persistenceContext", "true");
|
||||
listener.sessionCreated(context, flowSession);
|
||||
assertSessionBound();
|
||||
|
||||
public void testSingleState() {
|
||||
assertEquals("Table should only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
MockRequestContext context = new MockRequestContext();
|
||||
MockFlowSession flowSession = new MockFlowSession();
|
||||
listener.sessionCreated(context, flowSession);
|
||||
// Session created and bound to conversation
|
||||
final Session hibSession = (Session) context.getConversationScope().get("hibernate.session");
|
||||
assertNotNull("Should have been populated", hibSession);
|
||||
listener.paused(context, ViewSelection.NULL_VIEW);
|
||||
assertSessionNotBound();
|
||||
|
||||
TestBean bean = new TestBean("Keith Donald");
|
||||
hibernateTemplate.save(bean);
|
||||
assertEquals("Table should still only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
|
||||
listener.sessionEnded(context, flowSession, null);
|
||||
assertEquals("Table should only have two rows", 2, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
}
|
||||
|
||||
public void testMultipleState() {
|
||||
assertEquals("Table should only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
MockRequestContext context = new MockRequestContext();
|
||||
MockFlowSession flowSession = new MockFlowSession();
|
||||
listener.sessionCreated(context, flowSession);
|
||||
// Session bound to thread local variable
|
||||
listener.resumed(context);
|
||||
assertSessionBound();
|
||||
|
||||
TestBean bean1 = new TestBean("Keith Donald");
|
||||
hibernateTemplate.save(bean1);
|
||||
assertEquals("Table should still only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
listener.paused(context, ViewSelection.NULL_VIEW);
|
||||
|
||||
listener.resumed(context);
|
||||
TestBean bean2 = new TestBean("Keith Donald");
|
||||
hibernateTemplate.save(bean2);
|
||||
assertEquals("Table should still only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
|
||||
|
||||
listener.sessionEnded(context, flowSession, null);
|
||||
assertEquals("Table should only have two rows", 3, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
}
|
||||
hibernateTemplate.execute(new HibernateCallback() {
|
||||
public Object doInHibernate(Session session) throws HibernateException, SQLException {
|
||||
assertSame("Should have been original instance", hibSession, session);
|
||||
return null;
|
||||
}
|
||||
}, true);
|
||||
listener.paused(context, ViewSelection.NULL_VIEW);
|
||||
assertSessionNotBound();
|
||||
}
|
||||
|
||||
private DataSource getDataSource() {
|
||||
DriverManagerDataSource dataSource = new DriverManagerDataSource();
|
||||
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||
dataSource.setUrl("jdbc:hsqldb:mem:hspcl");
|
||||
dataSource.setUsername("sa");
|
||||
dataSource.setPassword("");
|
||||
return dataSource;
|
||||
}
|
||||
public void testFlowNotAPersistenceContext() {
|
||||
MockRequestContext context = new MockRequestContext();
|
||||
MockFlowSession flowSession = new MockFlowSession();
|
||||
listener.sessionCreated(context, flowSession);
|
||||
assertSessionNotBound();
|
||||
}
|
||||
|
||||
private void populateDataBase(DataSource dataSource) {
|
||||
Connection connection = null;
|
||||
public void testFlowEndsInSingleRequest() {
|
||||
assertEquals("Table should only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
MockRequestContext context = new MockRequestContext();
|
||||
MockFlowSession flowSession = new MockFlowSession();
|
||||
flowSession.getDefinitionInternal().getAttributeMap().put("persistenceContext", "true");
|
||||
listener.sessionCreated(context, flowSession);
|
||||
assertSessionBound();
|
||||
|
||||
TestBean bean = new TestBean("Keith Donald");
|
||||
hibernateTemplate.save(bean);
|
||||
assertEquals("Table should still only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
|
||||
listener.sessionEnded(context, flowSession, null);
|
||||
assertEquals("Table should only have two rows", 2, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
assertSessionNotBound();
|
||||
assertFalse(flowSession.getScope().contains("hibernate.session"));
|
||||
}
|
||||
|
||||
public void testFlowSpansMultipleRequests() {
|
||||
assertEquals("Table should only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
MockRequestContext context = new MockRequestContext();
|
||||
MockFlowSession flowSession = new MockFlowSession();
|
||||
flowSession.getDefinitionInternal().getAttributeMap().put("persistenceContext", "true");
|
||||
listener.sessionCreated(context, flowSession);
|
||||
assertSessionBound();
|
||||
|
||||
TestBean bean1 = new TestBean("Keith Donald");
|
||||
hibernateTemplate.save(bean1);
|
||||
assertEquals("Table should still only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
listener.paused(context, ViewSelection.NULL_VIEW);
|
||||
assertSessionNotBound();
|
||||
|
||||
listener.resumed(context);
|
||||
TestBean bean2 = new TestBean("Keith Donald");
|
||||
hibernateTemplate.save(bean2);
|
||||
assertEquals("Table should still only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
assertSessionBound();
|
||||
|
||||
listener.sessionEnded(context, flowSession, null);
|
||||
assertEquals("Table should only have three rows", 3, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
assertFalse(flowSession.getScope().contains("hibernate.session"));
|
||||
|
||||
assertSessionNotBound();
|
||||
assertFalse(flowSession.getScope().contains("hibernate.session"));
|
||||
|
||||
}
|
||||
|
||||
public void testExceptionThrown() {
|
||||
assertEquals("Table should only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
MockRequestContext context = new MockRequestContext();
|
||||
MockFlowSession flowSession = new MockFlowSession();
|
||||
flowSession.getDefinitionInternal().getAttributeMap().put("persistenceContext", "true");
|
||||
listener.sessionCreated(context, flowSession);
|
||||
assertSessionBound();
|
||||
|
||||
TestBean bean1 = new TestBean("Keith Donald");
|
||||
hibernateTemplate.save(bean1);
|
||||
assertEquals("Table should still only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
listener.exceptionThrown(context, new FlowExecutionException("bla", "bla", "bla"));
|
||||
assertEquals("Table should still only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
assertSessionNotBound();
|
||||
|
||||
}
|
||||
|
||||
public void testCancelEndState() {
|
||||
assertEquals("Table should only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
MockRequestContext context = new MockRequestContext();
|
||||
MockFlowSession flowSession = new MockFlowSession();
|
||||
flowSession.getDefinitionInternal().getAttributeMap().put("persistenceContext", "true");
|
||||
listener.sessionCreated(context, flowSession);
|
||||
assertSessionBound();
|
||||
|
||||
TestBean bean = new TestBean("Keith Donald");
|
||||
hibernateTemplate.save(bean);
|
||||
assertEquals("Table should still only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
|
||||
EndState endState = new EndState(flowSession.getDefinitionInternal(), "cancel");
|
||||
endState.getAttributeMap().put("commit", Boolean.FALSE);
|
||||
flowSession.setState(endState);
|
||||
listener.sessionEnded(context, flowSession, null);
|
||||
assertEquals("Table should only have two rows", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
|
||||
assertSessionNotBound();
|
||||
assertFalse(flowSession.getScope().contains("hibernate.session"));
|
||||
}
|
||||
|
||||
private DataSource getDataSource() {
|
||||
DriverManagerDataSource dataSource = new DriverManagerDataSource();
|
||||
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||
dataSource.setUrl("jdbc:hsqldb:mem:hspcl");
|
||||
dataSource.setUsername("sa");
|
||||
dataSource.setPassword("");
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
private void populateDataBase(DataSource dataSource) {
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = dataSource.getConnection();
|
||||
connection.createStatement().execute("drop table T_BEAN if exists;");
|
||||
connection.createStatement().execute(
|
||||
"create table T_BEAN (ID integer primary key, NAME varchar(50) not null);");
|
||||
connection.createStatement().execute("insert into T_BEAN (ID, NAME) values (0, 'Ben Hale');");
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("SQL exception occurred acquiring connection", e);
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection = dataSource.getConnection();
|
||||
connection.createStatement().execute("drop table T_BEAN if exists;");
|
||||
connection.createStatement().execute(
|
||||
"create table T_BEAN (ID integer primary key, NAME varchar(50) not null);");
|
||||
connection.createStatement().execute("insert into T_BEAN (ID, NAME) values (0, 'Ben Hale');");
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("SQL exception occurred acquiring connection", e);
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SessionFactory getSessionFactory(DataSource dataSource) throws Exception {
|
||||
LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
|
||||
factory.setDataSource(dataSource);
|
||||
factory.setMappingLocations(new Resource[] { new ClassPathResource(
|
||||
"org/springframework/webflow/support/persistence/TestBean.hbm.xml") });
|
||||
factory.afterPropertiesSet();
|
||||
return (SessionFactory) factory.getObject();
|
||||
}
|
||||
|
||||
private void assertSessionNotBound() {
|
||||
assertNull(TransactionSynchronizationManager.getResource(sessionFactory));
|
||||
}
|
||||
|
||||
private void assertSessionBound() {
|
||||
assertNotNull(TransactionSynchronizationManager.getResource(sessionFactory));
|
||||
}
|
||||
|
||||
private SessionFactory getSessionFactory(DataSource dataSource) throws Exception {
|
||||
LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
|
||||
factory.setDataSource(dataSource);
|
||||
factory.setMappingLocations(new Resource[] { new ClassPathResource(
|
||||
"org/springframework/webflow/support/persistence/TestBean.hbm.xml") });
|
||||
factory.afterPropertiesSet();
|
||||
return (SessionFactory) factory.getObject();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user