Results 1 to 8 of 8

Thread: AbstractJpaTests and Atomikos JTA Manager

  1. #1

    Default AbstractJpaTests and Atomikos JTA Manager

    Hi guys,

    I am using the Atomikos JTA Manager as the transactionManager for my project. After configuring the transactionManager, I can't get the unit tests to run anymore. I always get an exception:

    [org.springframework.test.context.junit4.SpringMeth odRoadie] <openjpa-1.2.1-r752877:753278 nonfatal user error> org.apache.openjpa.persistence.TransactionRequired Exception: Can only perform operation while a transaction is active.

    Anyone else had this problem before? Any tips?

    Thanks in advance,

    Danniel.

  2. #2
    Join Date
    Jan 2008
    Location
    San Diego
    Posts
    780

    Default

    Have you configured your tests correctly so they are running in transactions?

  3. #3

    Default

    Quote Originally Posted by chudak View Post
    Have you configured your tests correctly so they are running in transactions?
    To be honest, can't really tell, couldn't find a tutorial on how to configure test cases with Atomikos.

    The spring setup for Atomikos is exactly the same they have in their examples, so I don't think that's the problem. Here's a sample test I created (please ignore the missing imports and package declarations):


    Code:
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations={"classpath:test-persistence.xml"})
    public class SampleTest extends AbstractJpaTests {
    
    	@Autowired
    	public void setEntityManagerFactory(@Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory) {
    		super.setEntityManagerFactory(entityManagerFactory);
    	}
    	
    	@Autowired
    	public void setTransactionManager(@Qualifier("transactionManager") PlatformTransactionManager transactionManager) {
    		super.setTransactionManager(transactionManager);
    	}
    	
    	
    	@Test
    	@Transactional
    	public void deleteTest() {
    		...code...
    		correctlyInjectedDAO.deleteMethod();
    		...code...
    	}
    
    }
    Thank you for your help, chudak.

  4. #4

    Default

    I don't know if this is important, so here it goes anyway. The deleteMethod() in my dao is using queries, in the following way:

    Code:
    Query query = entityManager.createQuery(someDeleteQLQuery);
    query.setParameter(firstParam, value);
    query.executeUpdate();
    I get the exception when running the third line. Atomikos is configured to intercept every method in my dao:

    Code:
    <bean id="bank" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    	<property name="transactionManager"><ref bean="springTransactionManager" /></property>
    	<property name="target"><ref bean="dao"  /></property>
    	<property name="transactionAttributes">
    		<props>
    			<prop key="*">PROPAGATION_REQUIRED, -Exception</prop>
    		</props>
    	</property>
    </bean>
    Using Atomikos 3.6.2, openjpa 1.2.1 and spring 2.5.6.

    Thanks again.

  5. #5
    Join Date
    Jan 2008
    Location
    San Diego
    Posts
    780

    Default

    Atomikos is just a transaction manager. There is nothing special about configuring atomikos versus any other transaction manager. If you have your atomikos TM configured in spring and wired to jpa correctly it should just work.

    A couple of things concern me...why is your test case wired up with either the entitymanagerfactory or the transaction manager? Your dao's should be wired up to the entitymanagerfactory (more on this in a second) and your transaction manager should be wired up to your entity manager factory.

    There was just a thread about this that I answered a few days ago where the dao was incorrectly using the entitymanagerfactory to create it's own entity manager rather than having this injected by spring.

    FWIW, I'm using JPA and Atomikos and I have a suite of functional tests that verify my dao's against a live database and it all works fine. One difference (althought it doesn't really matter) is that my functional tests just use the jpatransactionmanager--there doesn't seem to be much reason for using the full atomikos TM in dao testing..I only need it in my application because I'm doing (DB+JMS) transactions.

    I'd bet that you have something wired up or configured funky that is causing your problems.

  6. #6

    Default

    Hi chudak, thanks for the response.

    A couple of things concern me...why is your test case wired up with either the entitymanagerfactory or the transaction manager? Your dao's should be wired up to the entitymanagerfactory (more on this in a second) and your transaction manager should be wired up to your entity manager factory.
    I removed those injections, still getting the same exception. It seems that AbstractJpaTests are automatically injected with those beans. Anyway, I can't wire the entity manager factory to the transaction manager, because I'm using the JTA TM, not the JPA TM.

    FWIW, I'm using JPA and Atomikos and I have a suite of functional tests that verify my dao's against a live database and it all works fine. One difference (althought it doesn't really matter) is that my functional tests just use the jpatransactionmanager--there doesn't seem to be much reason for using the full atomikos TM in dao testing..I only need it in my application because I'm doing (DB+JMS) transactions.
    My point was to test if the Atomikos TM is correctly managing the transaction. In my case I don't have DB/JMS transactions, I have 2 different databases that I need to commit to inside the same transaction. But, in your case, how do you test if both resources (DB/JMS) are being correctly accessed?

    Again, thanks for the help.

  7. #7
    Join Date
    Jan 2008
    Location
    San Diego
    Posts
    780

    Default

    Quote Originally Posted by DannielWillian View Post
    Anyway, I can't wire the entity manager factory to the transaction manager, because I'm using the JTA TM, not the JPA TM.
    Note true. I'm wiring up the atomikos TM to my entity manager factory:

    Here's my config for JTA (I have a separate persistence.xml that I use to allow me to use the same persistence unit in a non XA environment).

    persistence.xml
    Code:
    <persistence-unit name="my-common-persistence" transaction-type="JTA">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <properties>
          <property name="hibernate.dialect" value="${hibernate.dialect}"/>
          <property name="hibernate.show_sql" value="false"/>
          <property name="hibernate.format_sql" value="true"/>
        </properties>
    Persistence base spring config (used by all applications):

    Code:
    <context:annotation-config/>
      <tx:annotation-driven/>
      <context:component-scan base-package="my.common.persistence"/>
      
      <!-- Process @PersistenceContext to inject entity manager factory -->
      <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
      
      <!-- Translate vanilla JPA persistence exceptions into something meaningful -->
      <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
    
      <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="jpaVendorAdapter">
          <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" >
          </bean>
        </property>
        <property name="jpaProperties" ref="jpaProperties"/>
      </bean>
      <!--  Dummy jpa properties that can be overridden -->
      <util:properties id="jpaProperties"/>
    My transaction manager config:

    Code:
    <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" 
              init-method="init" destroy-method="close">
             <property name="forceShutdown" value="false"/>
        </bean>
        
        <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.J2eeUserTransaction">
            <property name="transactionTimeout" value="300"/>
        </bean>
        
        <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"
            depends-on="atomikosTransactionManager,atomikosUserTransaction">
            <property name="transactionManager" ref="atomikosTransactionManager"/>
            <property name="userTransaction" ref="atomikosUserTransaction"/>
            <!-- This is required for Spring Batch set set a custom isolation level when it runs -->
            <property name="allowCustomIsolationLevels" value="true"/>
        </bean>
    My application specific override configuration:

    Code:
     <!--  Override jpa properties-->
      <util:properties id="jpaProperties">
         <prop key="hibernate.current_session_context_class">jta</prop>
         <prop key="hibernate.transaction.manager_lookup_class">com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup</prop>
      </util:properties>
      
      <bean id="dataSource" class="com.atomikos.jdbc.nonxa.AtomikosNonXADataSourceBean"
            destroy-method="close">
        <property name="uniqueResourceName" value="MyPrimary Datasource"/>
        <property name="driverClassName" value="${my.database.driver}"/>
        <property name="url" value="${my.database.url}"/>
        <property name="user" value="${my.database.user}"/>
        <property name="password" value="${my.database.password}"/>
        <property name="testQuery" value="select 1"/>
        <property name="maxPoolSize" value="50"/>
        <property name="minPoolSize" value="20"/>
        <property name="reapTimeout" value="0"></property>      
      </bean>
    My Base DAO looks like this:

    Code:
    public abstract class BaseAbstractDAO<K, E> implements AbstractDAO<K, E> 
    {
        protected Class<E> entityClass;
        
        @PersistenceContext
        protected EntityManager entityManager;
         @SuppressWarnings({ "unchecked" })
        public BaseAbstractDAO() 
        {
            ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
            this.entityClass = (Class<E>) genericSuperclass.getActualTypeArguments()[1];
        }
        
        public void setEntityManager(EntityManager manager)
        {
            this.entityManager = manager;
        }
    
        @Override
        public void persist(E entity) 
        {
            entityManager.persist(entity);
        }
    
        @Override
        public void remove(E entity) 
        {
            entityManager.remove(entity);
        }
    
        @Override
        public E findById(K id) 
        {
            return entityManager.find(entityClass, id);
        }
        
        @Override
        public void flush()
        {
            entityManager.flush();
        }
       ....
    }
    And one of my dao's:

    Code:
    @Repository("clientDao")
    public class ClientDAOImpl extends BaseAbstractDAO<Long, Client> implements ClientDAO
    {
    ....
    }
    The component scan and persistence annotation post processor automatically construct all my beans and inject them with the spring managed entitymanager.

    My functional test base class (that all my functional tests extend from ) look like this:

    Code:
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = {"classpath:spring/applicationContext.xml"})
    @TransactionConfiguration(transactionManager="transactionManager", defaultRollback=true)
    @Transactional
    public abstract class FunctionalTestBase
    {
        @Autowired
        protected ClientDAO clientDao;
        ....
    }
    My actual functional tests just extend from this class and exercise the dao's:

    Code:
    public class ClientDaoImplFunctionalTest extends FunctionalTestBase
    {
        @Test
        public void testCreateClient()
        {
            Client client = new Client();
            client.setPassword("password");
            client.setUsername("username");
            this.clientDao.persist(client);
            this.clientDao.flush();
            
            Client retrieved = this.clientDao.findById(client.getId());
            Assert.assertNotNull(retrieved);
            Assert.assertEquals(client.getUsername(), retrieved.getUsername());
            Assert.assertEquals(client.getPassword(), retrieved.getPassword());
        }
    If you had all of the above spring config in your application context file and started this test, your dao's would be constructed and injected into this class and then you could use them in functional tests.

  8. #8

    Default

    Hi chudak,

    Thanks for all the help. I managed to get the tests running, and you were right, it was a configuration problem. I went over again the openjpa documentation, and noticed that I left out the XA Transaction config from persistence.xml. So, here's what I done to fix it:

    in persistence.xml, inside the persistence-unit tag, added the following attribute: transaction-type="JTA":

    Code:
    <persistence-unit name="firstUnit" transaction-type="JTA">
    Added these two properties to the persistence-unit:
    Code:
    <property name="openjpa.TransactionMode" value="managed"/>
    <property name="openjpa.ManagedRuntime" value="invocation(TransactionManagerMethod=com.atomikos.icatch.jta.TransactionManagerImp.getTransactionManager)"/>
    And everything is working fine now.

    Again, thank you very much for all your help.

    Best regards,

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •