/*
* Copyright 2004-2014 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.webflow.persistence;
import javax.sql.DataSource;
import junit.framework.TestCase;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.orm.hibernate4.HibernateCallback;
import org.springframework.orm.hibernate4.HibernateTemplate;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.webflow.engine.EndState;
import org.springframework.webflow.execution.FlowExecutionException;
import org.springframework.webflow.test.MockFlowSession;
import org.springframework.webflow.test.MockRequestContext;
/**
* Tests for {@link HibernateFlowExecutionListener}
*
* @author Ben Hale
*/
public class HibernateFlowExecutionListenerTests extends TestCase {
private SessionFactory sessionFactory;
private JdbcTemplate jdbcTemplate;
private HibernateTemplate hibernateTemplate;
private HibernateFlowExecutionListener hibernateListener;
protected void setUp() throws Exception {
DataSource dataSource = getDataSource();
populateDataBase(dataSource);
jdbcTemplate = new JdbcTemplate(dataSource);
sessionFactory = getSessionFactory(dataSource);
hibernateTemplate = new HibernateTemplate(sessionFactory);
hibernateTemplate.setCheckWriteOperations(false);
HibernateTransactionManager tm = new HibernateTransactionManager(sessionFactory);
hibernateListener = new HibernateFlowExecutionListener(sessionFactory, tm);
}
public void testSameSession() {
MockRequestContext context = new MockRequestContext();
MockFlowSession flowSession = new MockFlowSession();
flowSession.getDefinition().getAttributes().put("persistenceContext", "true");
hibernateListener.sessionStarting(context, flowSession, null);
context.setActiveSession(flowSession);
assertSessionBound();
// Session created and bound to conversation
final Session hibSession = (Session) flowSession.getScope().get("persistenceContext");
assertNotNull("Should have been populated", hibSession);
hibernateListener.paused(context);
assertSessionNotBound();
// Session bound to thread local variable
hibernateListener.resuming(context);
assertSessionBound();
hibernateTemplate.executeWithNativeSession(new HibernateCallback<Object>() {
public Object doInHibernate(Session session) {
assertSame("Should have been original instance", hibSession, session);
return null;
}
});
hibernateListener.paused(context);
assertSessionNotBound();
}
public void testFlowNotAPersistenceContext() {
MockRequestContext context = new MockRequestContext();
MockFlowSession flowSession = new MockFlowSession();
hibernateListener.sessionStarting(context, flowSession, null);
assertSessionNotBound();
}
public void testFlowCommitsInSingleRequest() {
assertEquals("Table should only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
MockRequestContext context = new MockRequestContext();
MockFlowSession flowSession = new MockFlowSession();
flowSession.getDefinition().getAttributes().put("persistenceContext", "true");
hibernateListener.sessionStarting(context, flowSession, null);
context.setActiveSession(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(), "success");
endState.getAttributes().put("commit", true);
flowSession.setState(endState);
hibernateListener.sessionEnding(context, flowSession, "success", null);
hibernateListener.sessionEnded(context, flowSession, "success", null);
assertEquals("Table should only have two rows", 2, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
assertSessionNotBound();
}
public void testFlowCommitsAfterMultipleRequests() {
assertEquals("Table should only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
MockRequestContext context = new MockRequestContext();
MockFlowSession flowSession = new MockFlowSession();
flowSession.getDefinition().getAttributes().put("persistenceContext", "true");
hibernateListener.sessionStarting(context, flowSession, null);
context.setActiveSession(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"));
hibernateListener.paused(context);
assertSessionNotBound();
hibernateListener.resuming(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();
EndState endState = new EndState(flowSession.getDefinitionInternal(), "success");
endState.getAttributes().put("commit", true);
flowSession.setState(endState);
hibernateListener.sessionEnding(context, flowSession, "success", null);
hibernateListener.sessionEnded(context, flowSession, "success", null);
assertEquals("Table should only have three rows", 3, 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.getDefinition().getAttributes().put("persistenceContext", "true");
hibernateListener.sessionStarting(context, flowSession, null);
context.setActiveSession(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.getAttributes().put("commit", false);
flowSession.setState(endState);
hibernateListener.sessionEnding(context, flowSession, "success", null);
hibernateListener.sessionEnded(context, flowSession, "cancel", null);
assertEquals("Table should only have two rows", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
assertSessionNotBound();
}
public void testNoCommitAttributeSetOnEndState() {
assertEquals("Table should only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
MockRequestContext context = new MockRequestContext();
MockFlowSession flowSession = new MockFlowSession();
flowSession.getDefinition().getAttributes().put("persistenceContext", "true");
hibernateListener.sessionStarting(context, flowSession, null);
context.setActiveSession(flowSession);
assertSessionBound();
EndState endState = new EndState(flowSession.getDefinitionInternal(), "cancel");
flowSession.setState(endState);
hibernateListener.sessionEnding(context, flowSession, "success", null);
hibernateListener.sessionEnded(context, flowSession, "cancel", null);
assertEquals("Table should only have three rows", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
assertSessionNotBound();
}
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.getDefinition().getAttributes().put("persistenceContext", "true");
hibernateListener.sessionStarting(context, flowSession, null);
context.setActiveSession(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"));
hibernateListener.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 testExceptionThrownWithNothingBound() {
assertEquals("Table should only have one row", 1, jdbcTemplate.queryForInt("select count(*) from T_BEAN"));
MockRequestContext context = new MockRequestContext();
MockFlowSession flowSession = new MockFlowSession();
flowSession.getDefinition().getAttributes().put("persistenceContext", "true");
assertSessionNotBound();
hibernateListener.exceptionThrown(context, new FlowExecutionException("foo", "bar", "test"));
assertSessionNotBound();
}
public void testLazyInitializedCollection() {
MockRequestContext context = new MockRequestContext();
MockFlowSession flowSession = new MockFlowSession();
flowSession.getDefinition().getAttributes().put("persistenceContext", "true");
hibernateListener.sessionStarting(context, flowSession, null);
context.setActiveSession(flowSession);
assertSessionBound();
TestBean bean = hibernateTemplate.get(TestBean.class, Long.valueOf(0));
assertFalse("addresses should not be initialized", Hibernate.isInitialized(bean.getAddresses()));
hibernateListener.paused(context);
assertFalse("addresses should not be initialized", Hibernate.isInitialized(bean.getAddresses()));
Hibernate.initialize(bean.getAddresses());
assertTrue("addresses should be initialized", Hibernate.isInitialized(bean.getAddresses()));
}
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) throws Exception {
ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
databasePopulator.addScript(new ClassPathResource("test-data.sql", this.getClass()));
DataSourceInitializer initializer = new DataSourceInitializer();
initializer.setDataSource(dataSource);
initializer.setDatabasePopulator(databasePopulator);
initializer.afterPropertiesSet();
}
private SessionFactory getSessionFactory(DataSource dataSource) throws Exception {
LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setMappingLocations(new Resource[] {
new ClassPathResource("org/springframework/webflow/persistence/TestBean.hbm.xml"),
new ClassPathResource("org/springframework/webflow/persistence/TestAddress.hbm.xml") });
factory.afterPropertiesSet();
return factory.getObject();
}
private void assertSessionNotBound() {
assertNull(TransactionSynchronizationManager.getResource(sessionFactory));
}
private void assertSessionBound() {
assertNotNull(TransactionSynchronizationManager.getResource(sessionFactory));
}
}