// $Id: AggressiveReleaseTest.java 10977 2006-12-12 23:28:04Z steve.ebersole@jboss.com $
package org.hibernate.test.connections;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.Hibernate;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory;
import org.hibernate.internal.util.SerializationHelper;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.junit.Test;
import org.hibernate.testing.jta.TestingJtaBootstrap;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Implementation of AggressiveReleaseTest.
*
* @author Steve Ebersole
*/
public class AggressiveReleaseTest extends ConnectionManagementTestCase {
@Override
public void configure(Configuration cfg) {
super.configure( cfg );
TestingJtaBootstrap.prepare( cfg.getProperties() );
cfg.setProperty( Environment.TRANSACTION_STRATEGY, CMTTransactionFactory.class.getName() );
cfg.setProperty( Environment.RELEASE_CONNECTIONS, ConnectionReleaseMode.AFTER_STATEMENT.toString() );
cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
cfg.setProperty( Environment.STATEMENT_BATCH_SIZE, "0" );
}
@Override
protected Session getSessionUnderTest() throws Throwable {
return openSession();
}
@Override
protected void reconnect(Session session) {
}
@Override
protected void prepare() throws Throwable {
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
}
@Override
protected void done() throws Throwable {
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
}
// Some additional tests specifically for the aggressive-release functionality...
@Test
public void testSerializationOnAfterStatementAggressiveRelease() throws Throwable {
prepare();
try {
Session s = getSessionUnderTest();
Silly silly = new Silly( "silly" );
s.save( silly );
// this should cause the CM to obtain a connection, and then release it
s.flush();
// We should be able to serialize the session at this point...
SerializationHelper.serialize( s );
s.delete( silly );
s.flush();
release( s );
}
finally {
done();
}
}
@Test
public void testSerializationFailsOnAfterStatementAggressiveReleaseWithOpenResources() throws Throwable {
prepare();
Session s = getSessionUnderTest();
Silly silly = new Silly( "silly" );
s.save( silly );
// this should cause the CM to obtain a connection, and then release it
s.flush();
// both scroll() and iterate() cause batching to hold on
// to resources, which should make aggressive-release not release
// the connection (and thus cause serialization to fail)
ScrollableResults sr = s.createQuery( "from Silly" ).scroll();
try {
SerializationHelper.serialize( s );
fail( "Serialization allowed on connected session; or aggressive release released connection with open resources" );
}
catch( IllegalStateException e ) {
// expected behavior
}
// getting the first row only because SybaseASE15Dialect throws NullPointerException
// if data is not read before closing the ResultSet
sr.next();
// Closing the ScrollableResults does currently force batching to
// aggressively release the connection
sr.close();
SerializationHelper.serialize( s );
s.delete( silly );
s.flush();
release( s );
done();
}
@Test
public void testQueryIteration() throws Throwable {
prepare();
Session s = getSessionUnderTest();
Silly silly = new Silly( "silly" );
s.save( silly );
s.flush();
Iterator itr = s.createQuery( "from Silly" ).iterate();
assertTrue( itr.hasNext() );
Silly silly2 = ( Silly ) itr.next();
assertEquals( silly, silly2 );
Hibernate.close( itr );
itr = s.createQuery( "from Silly" ).iterate();
Iterator itr2 = s.createQuery( "from Silly where name = 'silly'" ).iterate();
assertTrue( itr.hasNext() );
assertEquals( silly, itr.next() );
assertTrue( itr2.hasNext() );
assertEquals( silly, itr2.next() );
Hibernate.close( itr );
Hibernate.close( itr2 );
s.delete( silly );
s.flush();
release( s );
done();
}
@Test
public void testQueryScrolling() throws Throwable {
prepare();
Session s = getSessionUnderTest();
Silly silly = new Silly( "silly" );
s.save( silly );
s.flush();
ScrollableResults sr = s.createQuery( "from Silly" ).scroll();
assertTrue( sr.next() );
Silly silly2 = ( Silly ) sr.get( 0 );
assertEquals( silly, silly2 );
sr.close();
sr = s.createQuery( "from Silly" ).scroll();
ScrollableResults sr2 = s.createQuery( "from Silly where name = 'silly'" ).scroll();
assertTrue( sr.next() );
assertEquals( silly, sr.get( 0 ) );
assertTrue( sr2.next() );
assertEquals( silly, sr2.get( 0 ) );
sr.close();
sr2.close();
s.delete( silly );
s.flush();
release( s );
done();
}
@Test
public void testSuppliedConnection() throws Throwable {
prepare();
Connection originalConnection = sessionFactory().getServiceRegistry().getService( ConnectionProvider.class ).getConnection();
Session session = sessionFactory().withOptions().connection( originalConnection ).openSession();
Silly silly = new Silly( "silly" );
session.save( silly );
// this will cause the connection manager to cycle through the aggressive release logic;
// it should not release the connection since we explicitly suplied it ourselves.
session.flush();
assertTrue( session.isConnected() );
session.delete( silly );
session.flush();
release( session );
done();
sessionFactory().getServiceRegistry().getService( ConnectionProvider.class ).closeConnection( originalConnection );
}
@Test
public void testConnectionMaintanenceDuringFlush() throws Throwable {
prepare();
Session s = getSessionUnderTest();
s.beginTransaction();
List entities = new ArrayList();
for ( int i = 0; i < 10; i++ ) {
Other other = new Other( "other-" + i );
Silly silly = new Silly( "silly-" + i, other );
entities.add( silly );
s.save( silly );
}
s.flush();
Iterator itr = entities.iterator();
while ( itr.hasNext() ) {
Silly silly = ( Silly ) itr.next();
silly.setName( "new-" + silly.getName() );
silly.getOther().setName( "new-" + silly.getOther().getName() );
}
long initialCount = sessionFactory().getStatistics().getConnectCount();
s.flush();
assertEquals( "connection not maintained through flush", initialCount + 1, sessionFactory().getStatistics().getConnectCount() );
s.createQuery( "delete from Silly" ).executeUpdate();
s.createQuery( "delete from Other" ).executeUpdate();
s.getTransaction().commit();
release( s );
done();
}
}