Package org.springframework.orm.hibernate4

Source Code of org.springframework.orm.hibernate4.HibernateTransactionManagerTests$ImplementingSession

/*
* Copyright 2002-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.orm.hibernate4;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import javax.sql.DataSource;
import javax.transaction.TransactionManager;
import javax.transaction.TransactionSynchronizationRegistry;
import javax.transaction.UserTransaction;

import org.hibernate.FlushMode;
import org.hibernate.Interceptor;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionBuilder;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory;
import org.hibernate.exception.ConstraintViolationException;
import org.junit.After;
import org.junit.Test;
import org.mockito.InOrder;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.jdbc.datasource.ConnectionHolder;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy;
import org.springframework.transaction.CannotCreateTransactionException;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.UnexpectedRollbackException;
import org.springframework.transaction.jta.JtaTransactionManager;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.transaction.support.TransactionTemplate;

import static org.junit.Assert.*;
import static org.mockito.BDDMockito.*;

/**
* @author Juergen Hoeller
* @since 3.2
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public class HibernateTransactionManagerTests {

  @After
  public void tearDown() {
    assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty());
    assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
    assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
    assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
  }

  @Test
  public void testTransactionCommit() throws Exception {
    final DataSource ds = mock(DataSource.class);
    Connection con = mock(Connection.class);
    final SessionFactory sf = mock(SessionFactory.class);
    final ImplementingSession session = mock(ImplementingSession.class);
    Transaction tx = mock(Transaction.class);
    Query query = mock(Query.class);

    final List list = new ArrayList();
    list.add("test");
    given(con.getTransactionIsolation()).willReturn(Connection.TRANSACTION_READ_COMMITTED);
    given(sf.openSession()).willReturn(session);
    given(session.getTransaction()).willReturn(tx);
    given(session.connection()).willReturn(con);
    given(session.isOpen()).willReturn(true);
    given(session.createQuery("some query string")).willReturn(query);
    given(query.list()).willReturn(list);
    given(session.isConnected()).willReturn(true);

    LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean() {
      @Override
      protected SessionFactory buildSessionFactory(LocalSessionFactoryBuilder sfb) {
        return sf;
      }
    };
    lsfb.afterPropertiesSet();
    final SessionFactory sfProxy = lsfb.getObject();

    HibernateTransactionManager tm = new HibernateTransactionManager();
    tm.setSessionFactory(sfProxy);
    tm.setDataSource(ds);
    TransactionTemplate tt = new TransactionTemplate(tm);
    tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);
    tt.setTimeout(10);
    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sfProxy));
    assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());

    Object result = tt.execute(new TransactionCallback() {
      @Override
      public Object doInTransaction(TransactionStatus status) {
        assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sfProxy));
        assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds));
        assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
        assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
        Session session = ((SessionHolder) TransactionSynchronizationManager.getResource(sfProxy)).getSession();
        return session.createQuery("some query string").list();
      }
    });
    assertTrue("Correct result list", result == list);

    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sfProxy));
    assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());

    verify(con).setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
    verify(con).setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
    verify(tx).setTimeout(10);
    verify(tx).begin();
    verify(tx).commit();
    verify(session).close();
  }

  @Test
  public void testTransactionRollback() throws Exception {
    Connection con = mock(Connection.class);
    final SessionFactory sf = mock(SessionFactory.class);
    ImplementingSession session = mock(ImplementingSession.class);
    Transaction tx = mock(Transaction.class);

    given(sf.openSession()).willReturn(session);
    given(session.beginTransaction()).willReturn(tx);
    given(session.isOpen()).willReturn(true);
    given(session.isConnected()).willReturn(true);
    given(session.connection()).willReturn(con);

    PlatformTransactionManager tm = new HibernateTransactionManager(sf);
    TransactionTemplate tt = new TransactionTemplate(tm);
    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());

    try {
      tt.execute(new TransactionCallback() {
        @Override
        public Object doInTransaction(TransactionStatus status) {
          assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
          throw new RuntimeException("application exception");
        }
      });
      fail("Should have thrown RuntimeException");
    }
    catch (RuntimeException ex) {
      // expected
    }

    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
    verify(session).close();
    verify(tx).rollback();
  }

  @Test
  public void testTransactionRollbackOnly() throws Exception {
    Connection con = mock(Connection.class);
    final SessionFactory sf = mock(SessionFactory.class);
    ImplementingSession session = mock(ImplementingSession.class);
    Transaction tx = mock(Transaction.class);

    given(sf.openSession()).willReturn(session);
    given(session.beginTransaction()).willReturn(tx);
    given(session.isOpen()).willReturn(true);
    given(session.getFlushMode()).willReturn(FlushMode.AUTO);
    given(session.isConnected()).willReturn(true);
    given(session.connection()).willReturn(con);

    PlatformTransactionManager tm = new HibernateTransactionManager(sf);
    TransactionTemplate tt = new TransactionTemplate(tm);
    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));

    tt.execute(new TransactionCallback() {
      @Override
      public Object doInTransaction(TransactionStatus status) {
        assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
        Session session = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
        session.flush();
        status.setRollbackOnly();
        return null;
      }
    });

    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    verify(session).flush();
    verify(session).close();
    verify(tx).rollback();
  }

  @Test
  public void testParticipatingTransactionWithCommit() throws Exception {
    Connection con = mock(Connection.class);
    final SessionFactory sf = mock(SessionFactory.class);
    final ImplementingSession session = mock(ImplementingSession.class);
    Transaction tx = mock(Transaction.class);

    given(sf.openSession()).willReturn(session);
    given(session.beginTransaction()).willReturn(tx);
    given(session.isOpen()).willReturn(true);
    given(session.getFlushMode()).willReturn(FlushMode.AUTO);
    given(session.isConnected()).willReturn(true);
    given(session.connection()).willReturn(con);

    LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean() {
      @Override
      protected SessionFactory buildSessionFactory(LocalSessionFactoryBuilder sfb) {
        return sf;
      }
    };
    lsfb.afterPropertiesSet();
    final SessionFactory sfProxy = lsfb.getObject();

    PlatformTransactionManager tm = new HibernateTransactionManager(sfProxy);
    final TransactionTemplate tt = new TransactionTemplate(tm);
    final List l = new ArrayList();
    l.add("test");

    Object result = tt.execute(new TransactionCallback() {
      @Override
      public Object doInTransaction(TransactionStatus status) {
        return tt.execute(new TransactionCallback() {
          @Override
          public Object doInTransaction(TransactionStatus status) {
            Session session = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
            session.flush();
            return l;
          }
        });
      }
    });
    assertTrue("Correct result list", result == l);

    verify(session).flush();
    verify(session).close();
    verify(tx).commit();
  }

  @Test
  public void testParticipatingTransactionWithRollback() throws Exception {
    Connection con = mock(Connection.class);
    final SessionFactory sf = mock(SessionFactory.class);
    ImplementingSession session = mock(ImplementingSession.class);
    Transaction tx = mock(Transaction.class);

    given(sf.openSession()).willReturn(session);
    given(session.beginTransaction()).willReturn(tx);
    given(session.isOpen()).willReturn(true);
    given(session.getFlushMode()).willReturn(FlushMode.AUTO);
    given(session.isConnected()).willReturn(true);
    given(session.connection()).willReturn(con);

    PlatformTransactionManager tm = new HibernateTransactionManager(sf);
    final TransactionTemplate tt = new TransactionTemplate(tm);
    try {
      tt.execute(new TransactionCallback() {
        @Override
        public Object doInTransaction(TransactionStatus status) {
          return tt.execute(new TransactionCallback() {
            @Override
            public Object doInTransaction(TransactionStatus status) {
              throw new RuntimeException("application exception");
            }
          });
        }
      });
      fail("Should have thrown RuntimeException");
    }
    catch (RuntimeException ex) {
      // expected
    }

    verify(session).close();
    verify(tx).rollback();
  }

  @Test
  public void testParticipatingTransactionWithRollbackOnly() throws Exception {
    Connection con = mock(Connection.class);
    final SessionFactory sf = mock(SessionFactory.class);
    ImplementingSession session = mock(ImplementingSession.class);
    Transaction tx = mock(Transaction.class);

    given(sf.openSession()).willReturn(session);
    given(session.beginTransaction()).willReturn(tx);
    given(session.isOpen()).willReturn(true);
    given(session.isConnected()).willReturn(true);
    given(session.connection()).willReturn(con);

    PlatformTransactionManager tm = new HibernateTransactionManager(sf);
    final TransactionTemplate tt = new TransactionTemplate(tm);
    final List l = new ArrayList();
    l.add("test");

    try {
      tt.execute(new TransactionCallback() {
        @Override
        public Object doInTransaction(TransactionStatus status) {
          return tt.execute(new TransactionCallback() {
            @Override
            public Object doInTransaction(TransactionStatus status) {
              status.setRollbackOnly();
              return null;
            }
          });
        }
      });
      fail("Should have thrown UnexpectedRollbackException");
    }
    catch (UnexpectedRollbackException ex) {
      // expected
    }

    verify(session).close();
    verify(tx).rollback();
  }

  @Test
  public void testParticipatingTransactionWithRequiresNew() throws Exception {
    final SessionFactory sf = mock(SessionFactory.class);
    ImplementingSession session1 = mock(ImplementingSession.class);
    ImplementingSession session2 = mock(ImplementingSession.class);
    Connection con = mock(Connection.class);
    Transaction tx = mock(Transaction.class);

    given(sf.openSession()).willReturn(session1, session2);
    given(session1.beginTransaction()).willReturn(tx);
    given(session1.isOpen()).willReturn(true);
    given(session2.beginTransaction()).willReturn(tx);
    given(session2.isOpen()).willReturn(true);
    given(session2.getFlushMode()).willReturn(FlushMode.AUTO);
    given(session1.isConnected()).willReturn(true);
    given(session1.connection()).willReturn(con);
    given(session2.isConnected()).willReturn(true);
    given(session2.connection()).willReturn(con);

    PlatformTransactionManager tm = new HibernateTransactionManager(sf);
    final TransactionTemplate tt = new TransactionTemplate(tm);
    tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);

    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    tt.execute(new TransactionCallback() {
      @Override
      public Object doInTransaction(TransactionStatus status) {
        final SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sf);
        assertTrue("Has thread session", holder != null);
        assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
        assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
        tt.execute(new TransactionCallback() {
          @Override
          public Object doInTransaction(TransactionStatus status) {
            Session session = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
            assertTrue("Not enclosing session", session != holder.getSession());
            session.flush();
            assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
            assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
            return null;
          }
        });
        assertTrue("Same thread session as before",
            holder.getSession() == ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession());
        assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
        assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
        return null;
      }
    });
    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));

    verify(session2).flush();
    verify(session1).close();
    verify(session2).close();
    verify(tx, times(2)).commit();
  }

  @Test
  public void testParticipatingTransactionWithNotSupported() throws Exception {
    final SessionFactory sf = mock(SessionFactory.class);
    ImplementingSession session = mock(ImplementingSession.class);
    Connection con = mock(Connection.class);
    Transaction tx = mock(Transaction.class);

    given(sf.openSession()).willReturn(session);
    given(session.getSessionFactory()).willReturn(sf);
    given(session.beginTransaction()).willReturn(tx);
    given(session.isOpen()).willReturn(true);
    given(session.getFlushMode()).willReturn(FlushMode.AUTO);
    given(session.isConnected()).willReturn(true);
    given(session.connection()).willReturn(con);

    HibernateTransactionManager tm = new HibernateTransactionManager(sf);
    final TransactionTemplate tt = new TransactionTemplate(tm);
    tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);

    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    tt.execute(new TransactionCallback() {
      @Override
      public Object doInTransaction(TransactionStatus status) {
        SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sf);
        assertTrue("Has thread session", holder != null);
        assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
        assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
        tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
        tt.execute(new TransactionCallback() {
          @Override
          public Object doInTransaction(TransactionStatus status) {
            assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
            assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
            assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
            return null;
          }
        });
        assertTrue("Same thread session as before",
            holder.getSession() == ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession());
        assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
        assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
        return null;
      }
    });
    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));

    verify(session).close();
    verify(tx).commit();
  }

  @Test
  public void testTransactionWithPropagationSupports() throws Exception {
    final SessionFactory sf = mock(SessionFactory.class);
    final Session session = mock(Session.class);

    given(sf.openSession()).willReturn(session);
    given(session.getSessionFactory()).willReturn(sf);
    given(session.getFlushMode()).willReturn(FlushMode.MANUAL);

    LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean() {
      @Override
      protected SessionFactory buildSessionFactory(LocalSessionFactoryBuilder sfb) {
        return sf;
      }
    };
    lsfb.afterPropertiesSet();
    final SessionFactory sfProxy = lsfb.getObject();

    PlatformTransactionManager tm = new HibernateTransactionManager(sfProxy);
    TransactionTemplate tt = new TransactionTemplate(tm);
    tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);
    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sfProxy));

    tt.execute(new TransactionCallback() {
      @Override
      public Object doInTransaction(TransactionStatus status) {
        assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sfProxy));
        assertTrue("Is not new transaction", !status.isNewTransaction());
        assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
        assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
        Session session = sf.openSession();
        session.flush();
        session.close();
        return null;
      }
    });

    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sfProxy));
    InOrder ordered = inOrder(session);
    ordered.verify(session).flush();
    ordered.verify(session).close();
  }

  @Test
  public void testTransactionWithPropagationSupportsAndCurrentSession() throws Exception {
    final SessionFactoryImplementor sf = mock(SessionFactoryImplementor.class);
    final Session session = mock(Session.class);

    given(sf.openSession()).willReturn(session);
    given(session.getSessionFactory()).willReturn(sf);
    given(session.getFlushMode()).willReturn(FlushMode.MANUAL);

    LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean() {
      @Override
      protected SessionFactory buildSessionFactory(LocalSessionFactoryBuilder sfb) {
        return sf;
      }
    };
    lsfb.afterPropertiesSet();
    final SessionFactory sfProxy = lsfb.getObject();

    PlatformTransactionManager tm = new HibernateTransactionManager(sfProxy);
    TransactionTemplate tt = new TransactionTemplate(tm);
    tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);
    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sfProxy));

    tt.execute(new TransactionCallback() {
      @Override
      public Object doInTransaction(TransactionStatus status) {
        assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sfProxy));
        assertTrue("Is not new transaction", !status.isNewTransaction());
        assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
        assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
        Session session = new SpringSessionContext(sf).currentSession();
        assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sfProxy));
        session.flush();
        return null;
      }
    });

    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sfProxy));
    InOrder ordered = inOrder(session);
    ordered.verify(session).flush();
    ordered.verify(session).close();
  }

  @Test
  public void testTransactionWithPropagationSupportsAndInnerTransaction() throws Exception {
    final SessionFactory sf = mock(SessionFactory.class);
    final ImplementingSession session1 = mock(ImplementingSession.class);
    final ImplementingSession session2 = mock(ImplementingSession.class);
    Connection con = mock(Connection.class);
    Transaction tx = mock(Transaction.class);

    given(sf.openSession()).willReturn(session1, session2);
    given(session1.getSessionFactory()).willReturn(sf);
    given(session1.getFlushMode()).willReturn(FlushMode.AUTO);
    given(session2.beginTransaction()).willReturn(tx);
    given(session2.connection()).willReturn(con);
    given(session2.getFlushMode()).willReturn(FlushMode.AUTO);
    given(session2.isOpen()).willReturn(true);
    given(session2.isConnected()).willReturn(true);

    LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean() {
      @Override
      protected SessionFactory buildSessionFactory(LocalSessionFactoryBuilder sfb) {
        return sf;
      }
    };
    lsfb.afterPropertiesSet();
    final SessionFactory sfProxy = lsfb.getObject();

    PlatformTransactionManager tm = new HibernateTransactionManager(sfProxy);
    TransactionTemplate tt = new TransactionTemplate(tm);
    tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);
    final TransactionTemplate tt2 = new TransactionTemplate(tm);
    tt2.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    tt.execute(new TransactionCallback() {
      @Override
      public Object doInTransaction(TransactionStatus status) {
        assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sfProxy));
        assertTrue("Is not new transaction", !status.isNewTransaction());
        assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
        assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
        Session session = sfProxy.openSession();
        assertSame(session1, session);
        tt2.execute(new TransactionCallback() {
          @Override
          public Object doInTransaction(TransactionStatus status) {
            assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
            assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
            Session session = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
            assertSame(session2, session);
            session.flush();
            return null;
          }
        });
        session.flush();
        session.close();
        assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
        assertFalse(TransactionSynchronizationManager.isActualTransactionActive());
        return null;
      }
    });
    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));

    verify(session1).flush();
    verify(session1).close();
    verify(session2).flush();
    verify(session2).close();
    verify(tx).commit();
  }

  @Test
  public void testTransactionCommitWithEntityInterceptor() throws Exception {
    Interceptor entityInterceptor = mock(Interceptor.class);
    Connection con = mock(Connection.class);
    final SessionFactory sf = mock(SessionFactory.class);
    ImplementingSession session = mock(ImplementingSession.class);
    SessionBuilder options = mock(SessionBuilder.class);
    Transaction tx = mock(Transaction.class);

    given(sf.withOptions()).willReturn(options);
    given(options.interceptor(entityInterceptor)).willReturn(options);
    given(options.openSession()).willReturn(session);
    given(session.beginTransaction()).willReturn(tx);
    given(session.isOpen()).willReturn(true);
    given(session.isConnected()).willReturn(true);
    given(session.connection()).willReturn(con);

    HibernateTransactionManager tm = new HibernateTransactionManager(sf);
    tm.setEntityInterceptor(entityInterceptor);
    tm.setAllowResultAccessAfterCompletion(true);
    TransactionTemplate tt = new TransactionTemplate(tm);
    tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());

    tt.execute(new TransactionCallbackWithoutResult() {
      @Override
      public void doInTransactionWithoutResult(TransactionStatus status) {
        assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
      }
    });

    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());

    verify(session).close();
    verify(tx).commit();
  }

  @Test
  public void testTransactionCommitWithEntityInterceptorBeanName() throws Exception {
    Interceptor entityInterceptor = mock(Interceptor.class);
    Interceptor entityInterceptor2 = mock(Interceptor.class);
    Connection con = mock(Connection.class);
    final SessionFactory sf = mock(SessionFactory.class);
    ImplementingSession session = mock(ImplementingSession.class);
    SessionBuilder options = mock(SessionBuilder.class);
    Transaction tx = mock(Transaction.class);

    given(sf.withOptions()).willReturn(options);
    given(options.interceptor(entityInterceptor)).willReturn(options);
    given(options.interceptor(entityInterceptor2)).willReturn(options);
    given(options.openSession()).willReturn(session);
    given(session.beginTransaction()).willReturn(tx);
    given(session.isOpen()).willReturn(true);
    given(session.isConnected()).willReturn(true);
    given(session.connection()).willReturn(con);

    BeanFactory beanFactory = mock(BeanFactory.class);
    given(beanFactory.getBean("entityInterceptor", Interceptor.class)).willReturn(
        entityInterceptor, entityInterceptor2);

    HibernateTransactionManager tm = new HibernateTransactionManager(sf);
    tm.setEntityInterceptorBeanName("entityInterceptor");
    tm.setBeanFactory(beanFactory);

    TransactionTemplate tt = new TransactionTemplate(tm);
    tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());

    for (int i = 0; i < 2; i++) {
      tt.execute(new TransactionCallbackWithoutResult() {
        @Override
        public void doInTransactionWithoutResult(TransactionStatus status) {
          assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
        }
      });
    }

    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());

    verify(session, times(2)).close();
    verify(tx, times(2)).commit();
  }

  @Test
  public void testTransactionCommitWithReadOnly() throws Exception {
    Connection con = mock(Connection.class);
    final SessionFactory sf = mock(SessionFactory.class);
    ImplementingSession session = mock(ImplementingSession.class);
    Transaction tx = mock(Transaction.class);
    Query query = mock(Query.class);

    final List list = new ArrayList();
    list.add("test");
    given(sf.openSession()).willReturn(session);
    given(session.beginTransaction()).willReturn(tx);
    given(session.connection()).willReturn(con);
    given(session.isOpen()).willReturn(true);
    given(session.createQuery("some query string")).willReturn(query);
    given(query.list()).willReturn(list);
    given(session.isConnected()).willReturn(true);
    given(con.isReadOnly()).willReturn(true);

    HibernateTransactionManager tm = new HibernateTransactionManager(sf);
    TransactionTemplate tt = new TransactionTemplate(tm);
    tt.setReadOnly(true);
    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());

    Object result = tt.execute(new TransactionCallback() {
      @Override
      public Object doInTransaction(TransactionStatus status) {
        assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
        assertTrue(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
        assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
        Session session = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
        return session.createQuery("some query string").list();
      }
    });
    assertTrue("Correct result list", result == list);

    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());

    verify(session).setFlushMode(FlushMode.MANUAL);
    verify(con).setReadOnly(true);
    verify(tx).commit();
    verify(con).setReadOnly(false);
    verify(session).close();
  }

  @Test
  public void testTransactionCommitWithFlushFailure() throws Exception {
    Connection con = mock(Connection.class);
    final SessionFactory sf = mock(SessionFactory.class);
    ImplementingSession session = mock(ImplementingSession.class);
    Transaction tx = mock(Transaction.class);

    given(sf.openSession()).willReturn(session);
    given(session.beginTransaction()).willReturn(tx);
    given(session.isOpen()).willReturn(true);
    SQLException sqlEx = new SQLException("argh", "27");
    Exception rootCause = null;
    ConstraintViolationException jdbcEx = new ConstraintViolationException("mymsg", sqlEx, null);
    rootCause = jdbcEx;
    willThrow(jdbcEx).given(tx).commit();
    given(session.isConnected()).willReturn(true);
    given(session.connection()).willReturn(con);

    HibernateTransactionManager tm = new HibernateTransactionManager(sf);
    TransactionTemplate tt = new TransactionTemplate(tm);
    final List l = new ArrayList();
    l.add("test");
    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());

    try {
      tt.execute(new TransactionCallback() {
        @Override
        public Object doInTransaction(TransactionStatus status) {
          assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
          return l;
        }
      });
      fail("Should have thrown DataIntegrityViolationException");
    }
    catch (DataIntegrityViolationException ex) {
      // expected
      assertEquals(rootCause, ex.getCause());
      assertTrue(ex.getMessage().contains("mymsg"));
    }

    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());

    verify(session).close();
    verify(tx).rollback();
  }

  @Test
  public void testTransactionCommitWithPreBound() throws Exception {
    final DataSource ds = mock(DataSource.class);
    Connection con = mock(Connection.class);
    final SessionFactory sf = mock(SessionFactory.class);
    final ImplementingSession session = mock(ImplementingSession.class);
    Transaction tx = mock(Transaction.class);

    given(session.beginTransaction()).willReturn(tx);
    given(session.isOpen()).willReturn(true);
    given(session.getFlushMode()).willReturn(FlushMode.MANUAL);
    given(session.connection()).willReturn(con);
    given(con.getTransactionIsolation()).willReturn(Connection.TRANSACTION_READ_COMMITTED);
    given(session.isConnected()).willReturn(true);

    HibernateTransactionManager tm = new HibernateTransactionManager();
    tm.setSessionFactory(sf);
    tm.setDataSource(ds);
    TransactionTemplate tt = new TransactionTemplate(tm);
    tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);
    final List l = new ArrayList();
    l.add("test");
    assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
    TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session));
    assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));

    Object result = tt.execute(new TransactionCallback() {
      @Override
      public Object doInTransaction(TransactionStatus status) {
        assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
        assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds));
        SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sf);
        assertTrue("Has thread transaction", sessionHolder.getTransaction() != null);
        Session sess = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
        assertEquals(session, sess);
        return l;
      }
    });
    assertTrue("Correct result list", result == l);

    assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
    SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sf);
    assertTrue("Hasn't thread transaction", sessionHolder.getTransaction() == null);
    TransactionSynchronizationManager.unbindResource(sf);
    assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());

    InOrder ordered = inOrder(session, con);
    ordered.verify(con).setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
    ordered.verify(session).setFlushMode(FlushMode.AUTO);
    ordered.verify(con).setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
    ordered.verify(session).setFlushMode(FlushMode.MANUAL);
    verify(tx).commit();
    verify(session).disconnect();
  }

  @Test
  public void testTransactionCommitWithPreBoundAndResultAccessAfterCommit() throws Exception {
    final DataSource ds = mock(DataSource.class);
    Connection con = mock(Connection.class);
    final SessionFactory sf = mock(SessionFactory.class);
    final ImplementingSession session = mock(ImplementingSession.class);
    Transaction tx = mock(Transaction.class);

    given(session.beginTransaction()).willReturn(tx);
    given(session.isOpen()).willReturn(true);
    given(session.getFlushMode()).willReturn(FlushMode.MANUAL);
    given(session.connection()).willReturn(con);
    given(con.getTransactionIsolation()).willReturn(Connection.TRANSACTION_READ_COMMITTED);
    given(con.getHoldability()).willReturn(ResultSet.CLOSE_CURSORS_AT_COMMIT);
    given(session.isConnected()).willReturn(true);

    HibernateTransactionManager tm = new HibernateTransactionManager();
    tm.setSessionFactory(sf);
    tm.setDataSource(ds);
    tm.setAllowResultAccessAfterCompletion(true);
    TransactionTemplate tt = new TransactionTemplate(tm);
    tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);
    final List l = new ArrayList();
    l.add("test");
    assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
    TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session));
    assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));

    Object result = tt.execute(new TransactionCallback() {
      @Override
      public Object doInTransaction(TransactionStatus status) {
        assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
        assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds));
        SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sf);
        assertTrue("Has thread transaction", sessionHolder.getTransaction() != null);
        Session sess = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
        assertEquals(session, sess);
        return l;
      }
    });
    assertTrue("Correct result list", result == l);

    assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
    SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sf);
    assertTrue("Hasn't thread transaction", sessionHolder.getTransaction() == null);
    TransactionSynchronizationManager.unbindResource(sf);
    assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());

    InOrder ordered = inOrder(session, con);
    ordered.verify(con).setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
    ordered.verify(con).setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT);
    ordered.verify(session).setFlushMode(FlushMode.AUTO);
    ordered.verify(con).setHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT);
    ordered.verify(con).setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
    ordered.verify(session).setFlushMode(FlushMode.MANUAL);
    verify(tx).commit();
  }

  @Test
  public void testTransactionRollbackWithPreBound() throws Exception {
    final DataSource ds = mock(DataSource.class);
    Connection con = mock(Connection.class);
    final SessionFactory sf = mock(SessionFactory.class);
    final ImplementingSession session = mock(ImplementingSession.class);
    final Transaction tx1 = mock(Transaction.class);
    final Transaction tx2 = mock(Transaction.class);

    given(session.beginTransaction()).willReturn(tx1, tx2);
    given(session.isOpen()).willReturn(true);
    given(session.getFlushMode()).willReturn(FlushMode.MANUAL);
    given(session.isConnected()).willReturn(true);
    given(session.connection()).willReturn(con);

    HibernateTransactionManager tm = new HibernateTransactionManager();
    tm.setSessionFactory(sf);
    tm.setDataSource(ds);
    final TransactionTemplate tt = new TransactionTemplate(tm);
    assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
    TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session));
    assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));

    try {
      tt.execute(new TransactionCallbackWithoutResult() {
        @Override
        public void doInTransactionWithoutResult(TransactionStatus status) {
          assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
          assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds));
          SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sf);
          assertEquals(tx1, sessionHolder.getTransaction());
          tt.execute(new TransactionCallbackWithoutResult() {
            @Override
            public void doInTransactionWithoutResult(TransactionStatus status) {
              status.setRollbackOnly();
              Session sess = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
              assertEquals(session, sess);
            }
          });
        }
      });
      fail("Should have thrown UnexpectedRollbackException");
    }
    catch (UnexpectedRollbackException ex) {
      // expected
    }

    assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
    SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sf);
    assertTrue("Hasn't thread transaction", sessionHolder.getTransaction() == null);
    assertTrue("Not marked rollback-only", !sessionHolder.isRollbackOnly());

    tt.execute(new TransactionCallbackWithoutResult() {
      @Override
      public void doInTransactionWithoutResult(TransactionStatus status) {
        assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
        assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds));
        SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sf);
        assertEquals(tx2, sessionHolder.getTransaction());
        Session sess = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
        assertEquals(session, sess);
      }
    });

    assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
    assertTrue("Hasn't thread transaction", sessionHolder.getTransaction() == null);
    TransactionSynchronizationManager.unbindResource(sf);
    assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());

    verify(tx1).rollback();
    verify(tx2).commit();
    InOrder ordered = inOrder(session);
    ordered.verify(session).clear();
    ordered.verify(session).setFlushMode(FlushMode.AUTO);
    ordered.verify(session).setFlushMode(FlushMode.MANUAL);
    ordered.verify(session).disconnect();
  }

  @Test
  public void testTransactionRollbackWithHibernateManagedSession() throws Exception {
    final SessionFactory sf = mock(SessionFactory.class);
    final Session session = mock(Session.class);
    final Transaction tx1 = mock(Transaction.class);
    final Transaction tx2 = mock(Transaction.class);

    given(sf.getCurrentSession()).willReturn(session);
    given(session.isOpen()).willReturn(true);
    given(session.getTransaction()).willReturn(tx1, tx2);
    given(session.beginTransaction()).willReturn(tx1, tx2);
    given(session.getFlushMode()).willReturn(FlushMode.MANUAL);

    HibernateTransactionManager tm = new HibernateTransactionManager();
    tm.setSessionFactory(sf);
    tm.setPrepareConnection(false);
    tm.setHibernateManagedSession(true);
    final TransactionTemplate tt = new TransactionTemplate(tm);

    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));

    try {
      tt.execute(new TransactionCallbackWithoutResult() {
        @Override
        public void doInTransactionWithoutResult(TransactionStatus status) {
          assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
          tt.execute(new TransactionCallbackWithoutResult() {
            @Override
            public void doInTransactionWithoutResult(TransactionStatus status) {
              status.setRollbackOnly();
              Session sess = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
              assertEquals(session, sess);
            }
          });
        }
      });
      fail("Should have thrown UnexpectedRollbackException");
    }
    catch (UnexpectedRollbackException ex) {
      // expected
    }

    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));

    tt.execute(new TransactionCallbackWithoutResult() {
      @Override
      public void doInTransactionWithoutResult(TransactionStatus status) {
        assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
        Session sess = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
        assertEquals(session, sess);
      }
    });

    verify(tx1).rollback();
    verify(tx2).commit();
    InOrder ordered = inOrder(session);
    ordered.verify(session).setFlushMode(FlushMode.AUTO);
    ordered.verify(session).setFlushMode(FlushMode.MANUAL);
  }

  @Test
  public void testExistingTransactionWithPropagationNestedAndRollback() throws Exception {
    doTestExistingTransactionWithPropagationNestedAndRollback(false);
  }

  @Test
  public void testExistingTransactionWithManualSavepointAndRollback() throws Exception {
    doTestExistingTransactionWithPropagationNestedAndRollback(true);
  }

  private void doTestExistingTransactionWithPropagationNestedAndRollback(final boolean manualSavepoint)
      throws Exception {

    final DataSource ds = mock(DataSource.class);
    Connection con = mock(Connection.class);
    DatabaseMetaData md = mock(DatabaseMetaData.class);
    Savepoint sp = mock(Savepoint.class);
    final SessionFactory sf = mock(SessionFactory.class);
    ImplementingSession session = mock(ImplementingSession.class);
    Transaction tx = mock(Transaction.class);
    Query query = mock(Query.class);

    final List list = new ArrayList();
    list.add("test");
    given(sf.openSession()).willReturn(session);
    given(session.beginTransaction()).willReturn(tx);
    given(session.connection()).willReturn(con);
    given(session.isOpen()).willReturn(true);
    given(md.supportsSavepoints()).willReturn(true);
    given(con.getMetaData()).willReturn(md);
    given(con.setSavepoint(ConnectionHolder.SAVEPOINT_NAME_PREFIX + 1)).willReturn(sp);
    given(session.createQuery("some query string")).willReturn(query);
    given(query.list()).willReturn(list);
    given(session.isConnected()).willReturn(true);

    HibernateTransactionManager tm = new HibernateTransactionManager();
    tm.setNestedTransactionAllowed(true);
    tm.setSessionFactory(sf);
    tm.setDataSource(ds);
    final TransactionTemplate tt = new TransactionTemplate(tm);
    tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED);
    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());

    Object result = tt.execute(new TransactionCallback() {
      @Override
      public Object doInTransaction(TransactionStatus status) {
        assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
        assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds));
        if (manualSavepoint) {
          Object savepoint = status.createSavepoint();
          status.rollbackToSavepoint(savepoint);
        }
        else {
          tt.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
              assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
              assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds));
              status.setRollbackOnly();
            }
          });
        }
        Session session = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
        return session.createQuery("some query string").list();
      }
    });
    assertTrue("Correct result list", result == list);

    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());

    verify(con).setSavepoint(ConnectionHolder.SAVEPOINT_NAME_PREFIX + 1);
    verify(con).rollback(sp);
    verify(session).close();
    verify(tx).commit();
  }

  @Test
  public void testTransactionCommitWithNonExistingDatabase() throws Exception {
    final DriverManagerDataSource ds = new DriverManagerDataSource();
    LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean();
    lsfb.setDataSource(ds);
    Properties props = new Properties();
    props.setProperty("hibernate.dialect", HSQLDialect.class.getName());
    lsfb.setHibernateProperties(props);
    lsfb.afterPropertiesSet();
    final SessionFactory sf = lsfb.getObject();

    HibernateTransactionManager tm = new HibernateTransactionManager();
    tm.setSessionFactory(sf);
    tm.afterPropertiesSet();
    TransactionTemplate tt = new TransactionTemplate(tm);
    tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);
    tt.setTimeout(10);
    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());

    try {
      tt.execute(new TransactionCallback() {
        @Override
        public Object doInTransaction(TransactionStatus status) {
          assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
          assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds));
          Session session = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
          return session.createQuery("from java.lang.Object").list();
        }
      });
      fail("Should have thrown CannotCreateTransactionException");
    }
    catch (CannotCreateTransactionException ex) {
      // expected
    }

    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
  }

  @Test
  public void testTransactionCommitWithPreBoundSessionAndNonExistingDatabase() throws Exception {
    final DriverManagerDataSource ds = new DriverManagerDataSource();
    LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean();
    lsfb.setDataSource(ds);
    Properties props = new Properties();
    props.setProperty("hibernate.dialect", HSQLDialect.class.getName());
    lsfb.setHibernateProperties(props);
    lsfb.afterPropertiesSet();
    final SessionFactory sf = lsfb.getObject();

    HibernateTransactionManager tm = new HibernateTransactionManager();
    tm.setSessionFactory(sf);
    tm.afterPropertiesSet();
    TransactionTemplate tt = new TransactionTemplate(tm);
    tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);
    tt.setTimeout(10);
    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());

    Session session = sf.openSession();
    TransactionSynchronizationManager.bindResource(sf, new SessionHolder(session));
    try {
      tt.execute(new TransactionCallback() {
        @Override
        public Object doInTransaction(TransactionStatus status) {
          assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
          assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds));
          Session session = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
          return session.createQuery("from java.lang.Object").list();
        }
      });
      fail("Should have thrown CannotCreateTransactionException");
    }
    catch (CannotCreateTransactionException ex) {
      // expected
      SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sf);
      assertFalse(holder.isSynchronizedWithTransaction());
    }
    finally {
      TransactionSynchronizationManager.unbindResource(sf);
      session.close();
    }

    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
  }

  @Test
  public void testTransactionCommitWithNonExistingDatabaseAndLazyConnection() throws Exception {
    DriverManagerDataSource dsTarget = new DriverManagerDataSource();
    final LazyConnectionDataSourceProxy ds = new LazyConnectionDataSourceProxy();
    ds.setTargetDataSource(dsTarget);
    ds.setDefaultAutoCommit(true);
    ds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
    //ds.setDefaultTransactionIsolationName("TRANSACTION_READ_COMMITTED");

    LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean();
    lsfb.setDataSource(ds);
    Properties props = new Properties();
    props.setProperty("hibernate.dialect", HSQLDialect.class.getName());
    props.setProperty("hibernate.temp.use_jdbc_metadata_defaults", "false");
    lsfb.setHibernateProperties(props);
    lsfb.afterPropertiesSet();
    final SessionFactory sf = lsfb.getObject();

    HibernateTransactionManager tm = new HibernateTransactionManager();
    tm.setSessionFactory(sf);
    tm.afterPropertiesSet();
    TransactionTemplate tt = new TransactionTemplate(tm);
    tt.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);
    tt.setTimeout(10);
    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());

    tt.execute(new TransactionCallback() {
      @Override
      public Object doInTransaction(TransactionStatus status) {
        assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
        assertTrue("Has thread connection", TransactionSynchronizationManager.hasResource(ds));
        Session session = ((SessionHolder) TransactionSynchronizationManager.getResource(sf)).getSession();
        return session.createQuery("from java.lang.Object").list();
      }
    });

    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    assertTrue("Hasn't thread connection", !TransactionSynchronizationManager.hasResource(ds));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());
  }

  @Test
  public void testTransactionFlush() throws Exception {
    final SessionFactory sf = mock(SessionFactory.class);
    final Session session = mock(Session.class);
    Transaction tx = mock(Transaction.class);

    given(sf.openSession()).willReturn(session);
    given(session.beginTransaction()).willReturn(tx);

    HibernateTransactionManager tm = new HibernateTransactionManager(sf);
    tm.setPrepareConnection(false);
    TransactionTemplate tt = new TransactionTemplate(tm);
    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());

    tt.execute(new TransactionCallbackWithoutResult() {
      @Override
      public void doInTransactionWithoutResult(TransactionStatus status) {
        assertTrue("Has thread session", TransactionSynchronizationManager.hasResource(sf));
        assertFalse(TransactionSynchronizationManager.isCurrentTransactionReadOnly());
        assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
        status.flush();
      }
    });

    assertTrue("Hasn't thread session", !TransactionSynchronizationManager.hasResource(sf));
    assertTrue("JTA synchronizations not active", !TransactionSynchronizationManager.isSynchronizationActive());

    verify(session).flush();
    verify(tx).commit();
    verify(session).close();
  }

  @Test
  public void testSetJtaTransactionManager() throws Exception {
    DataSource ds = mock(DataSource.class);
    TransactionManager tm = mock(TransactionManager.class);
    UserTransaction ut = mock(UserTransaction.class);
    TransactionSynchronizationRegistry tsr = mock(TransactionSynchronizationRegistry.class);
    JtaTransactionManager jtm = new JtaTransactionManager();
    jtm.setTransactionManager(tm);
    jtm.setUserTransaction(ut);
    jtm.setTransactionSynchronizationRegistry(tsr);
    LocalSessionFactoryBuilder lsfb = new LocalSessionFactoryBuilder(ds);
    lsfb.setJtaTransactionManager(jtm);
    Object jtaPlatform = lsfb.getProperties().get(AvailableSettings.JTA_PLATFORM);
    assertNotNull(jtaPlatform);
    assertSame(tm, jtaPlatform.getClass().getMethod("retrieveTransactionManager").invoke(jtaPlatform));
    assertSame(ut, jtaPlatform.getClass().getMethod("retrieveUserTransaction").invoke(jtaPlatform));
    assertTrue(lsfb.getProperties().get(AvailableSettings.TRANSACTION_STRATEGY) instanceof CMTTransactionFactory);
  }

  @Test
  public void testSetTransactionManager() throws Exception {
    DataSource ds = mock(DataSource.class);
    TransactionManager tm = mock(TransactionManager.class);
    LocalSessionFactoryBuilder lsfb = new LocalSessionFactoryBuilder(ds);
    lsfb.setJtaTransactionManager(tm);
    Object jtaPlatform = lsfb.getProperties().get(AvailableSettings.JTA_PLATFORM);
    assertNotNull(jtaPlatform);
    assertSame(tm, jtaPlatform.getClass().getMethod("retrieveTransactionManager").invoke(jtaPlatform));
    assertTrue(lsfb.getProperties().get(AvailableSettings.TRANSACTION_STRATEGY) instanceof CMTTransactionFactory);
  }


  public interface ImplementingSession extends Session, SessionImplementor {
  }

}
TOP

Related Classes of org.springframework.orm.hibernate4.HibernateTransactionManagerTests$ImplementingSession

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.