1 2 Previous Next 17 Replies Latest reply on Oct 9, 2015 3:54 AM by tomjenkinson

    Narayana JTS with Spring in Tomee

    shabin8780

      I am trying to use Narayana JTS with Spring in Tomee to make transaction work across multiple instances. I don't want to use EJB and is trying to implement it in the Jacorb IIOP way. I tried to follow the spring integration part of http://narayana.io/docs/specs/server-integration-guide.pdf but even with a single instance and multiple datasource(for two different modules), 2pc doesn't seem to be working. What I am doing is in a single @Transactional method, I am accessing multiple xa-datasources. Success flow is working as expected. But even on exception, the data to the first data source is getting persisted and is not rolled back. This code is working fine if I am using tomee's container transaction manager. Also this is working on wildfly with jts configuration. Only issue is with jts and tomee. So I think it is an issue with my configuration. As this is not working I am not able to proceed to my next step which is to make transaction across multiple tomee instances work. So please advise on the configurations needed for this to work.

       

      These are my current configs:

       

      1. datasource definition

      <Resource name="jdbc/NGADataSourceAppln" auth="Container"
        type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000"
        description="Newgen sample application" username="app"
        password="a" driverClassName="org.apache.derby.jdbc.ClientXADataSource" JtaManaged="true" databaseName="GEMSDB"
        url="jdbc:derby://localhost:1527/GEMSDB;create=true" />
      
      <Resource name="jdbc/NGADSTechriLlocal" auth="Container"
        type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000"
        description="Newgen sample application for techri local" username="app"
        password="a" driverClassName="org.apache.derby.jdbc.ClientXADataSource" JtaManaged="true" databaseName="TechRILocalDB"
        url="jdbc:derby://localhost:1527/TechRILocalDB;create=true" />
      
      
      
      
      

       

      2.jndi lookup

      <jee:jndi-lookup id="jdbc/NGADataSourceAppln" jndi-name="jdbc/NGADataSourceAppln"/>
        <jee:jndi-lookup id="jdbc/NGADSTechriLlocal" jndi-name="jdbc/NGADSTechriLlocal"/>
      
      
      
      
      

       

      3. transactionManager and entityManagerFactory beans(similar definition is there for the other module with the other datasource)

      <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
          <property name="transactionManager">
            <ref bean="jbossTransactionManager"></ref>
          </property>
          <property name="userTransaction">
            <ref bean="jbossUserTransaction"></ref>
          </property>
          <property name="transactionSynchronizationRegistry">
            <ref bean="jbossTransactionSyncReg"></ref>
          </property>
        </bean>
      <bean id="jbossTransactionManager" class="com.arjuna.ats.internal.jta.transaction.jts.TransactionManagerImple">
        <property name="transactionTimeout" value="100"/>
      </bean>
      <bean id="jbossUserTransaction" class="com.arjuna.ats.internal.jta.transaction.jts.UserTransactionImple">
      </bean>
      <bean id="jbossTransactionSyncReg" class="com.arjuna.ats.internal.jta.transaction.jts.TransactionSynchronizationRegistryImple">
      </bean>
      
      <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="jtaDataSource" ref="jdbc/NGADataSourceAppln" />
        <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
        </property>
        <property name="jpaPropertyMap">
        <map>
      
        <entry key="hibernate.temp.use_jdbc_metadata_defaults" value="false" />
        <entry key="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect" />
      
        <entry key="hibernate.transaction.manager_lookup_class"
        value="test.JBossTransactionManagerLookup" />
        </map>
        </property>
        <property name="packagesToScan">
        <list>
        <value>ngsample.techri.**.*</value>
        </list>
        </property>
        </bean>
      
      
      
      
      

       

      4. TransactionManagerLookup

      package test;
      import java.util.Properties;
      import javax.transaction.Transaction;
      import javax.transaction.TransactionManager;
      import org.hibernate.HibernateException;
      import org.hibernate.transaction.TransactionManagerLookup;
      import org.springframework.context.annotation.Configuration;
      
      
      @Configuration
      public class JBossTransactionManagerLookup implements TransactionManagerLookup {
        private static final TransactionManager TRANSACTION_MANAGER_INSTANCE;
        static {
        TRANSACTION_MANAGER_INSTANCE = com.arjuna.ats.jta.TransactionManager.transactionManager();
        if (null == TRANSACTION_MANAGER_INSTANCE) {
        throw new HibernateException("Could not obtain arjuna Transaction Manager instance.");
        }
      
        }
      
      
        public TransactionManager getTransactionManager(Properties props) {
        return TRANSACTION_MANAGER_INSTANCE;
        }
      
      
        public String getUserTransactionName() {
        return null;
        }
      
      
        public Object getTransactionIdentifier(Transaction transaction) {
        return transaction;
        }
      }
      
      
      
      
      

       

      5.Setup code

      com.arjuna.orbportability.ORB myORB =
        com.arjuna.orbportability.ORB.getInstance("ServerSide");
        com.arjuna.orbportability.RootOA myOA =
        com.arjuna.orbportability.OA.getRootOA(myORB);
        myORB.initORB(new String[] {}, null);
        try {
        myOA.initOA();
        ORBManager.setORB(myORB);
      ORBManager.setPOA(myOA);
        //myOA.run();
        } catch (InvalidName e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        } catch (SystemException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        }
        }
      
      
      
      
      

       

      Also, if you can, please make a jts-spring quickstart.

        • 1. Re: Narayana JTS with Spring in Tomee
          tomjenkinson

          Hi Shabin,

           

          Please can you show how you are making the remote call? EJB code takes care of a lot of this for you and makes it really simple to do this, for example, are you extending CosTransactions::TransactionalObject in your IDL for your business objects? Also, please can you provide your jbossts-properties.xml?

           

          You might find some of our QA tests quite useful to take a look at as they do standalone transaction propagation.

          narayana/Issues0001.idl at master · jbosstm/narayana · GitHub

          https://github.com/jbosstm/narayana/blob/bc2a5faaefa848041f2bb22080b8c708af8baec6/qa/tests/src/org/jboss/jbossts/qa/Issues0001Clients/Client0001.java

          narayana/Server0001.java at bc2a5faaefa848041f2bb22080b8c708af8baec6 · jbosstm/narayana · GitHub

          https://github.com/jbosstm/narayana/blob/bc2a5faaefa848041f2bb22080b8c708af8baec6/qa/tests/src/org/jboss/jbossts/qa/Issues0001Impls/CounterImpl0001.java

           

          There is quite a lot of work that is taken care of by the container including the Resources from https://github.com/jbosstm/narayana/blob/master/ArjunaJTS/idl/src/main/idl/omg/CosTransactions.idl - is there a reason why you don't want to use WildFly (or any other EE container that Narayana could integrate with?)


          Thanks,

          Tom

          • 2. Re: Narayana JTS with Spring in Tomee
            mmusgrov

            If you want to use datasources in a standalone environment then you will need to use our transactional driver (Narayana Project Documentation). We have some unit tests (such as narayana/JDBC2Test.java at master · jbosstm/narayana · GitHub) that show how to use it in JTA mode (but it should be the same with JTS). And for JTS we have a trailmap (quickstart/ArjunaJTS/trailmap at master · jbosstm/quickstart · GitHub) that includes JDBC accesses..

            • 3. Re: Narayana JTS with Spring in Tomee
              shabin8780

              Hi Tom,

               

              As I said, currently I am not looking into the remote call part. Now I am just accessing different datasources in a single transaction. So I don't have any remote call. I am directly calling the service method of another module which is in the same instance but uses another datasource.

               

              @Autowired
              private ModuleService moduleService;
              @Transactional
              public void testModularFlow(LocalVO localVO) {
                  ModuleVO vo = new ModuleVO();
                  vo.setId("1");
                  vo.setNumberField(121);
                  vo.setStringField("aaa");
                  moduleService.addModule(vo); //this will insert data in another datasource
                  localDAO.addLocal(localVO);
              }
              
              
              
              
              

               

              Now if I throw some exception in the addLocal() method, data inserted in addModule() is always getting persisted.

              Also, sorry to say I am not aware of jbossts-properties.xml. It was not mentioned in the server-integration-guide.

               

              We are trying to implement some jts mechanism which can be used irrespective of the jee container. That is why we are trying out this in the Tomee container.

               

              Edit: Actually I tested in now without the moduleService.addModule() call and added an exception in the service method. Now localVO object is getting persisted no matter what. So @Transactional is not working in a single method itself. I am really confused now.

              @Transactional
              public void testModularFlow(LocalVO localVO) {
                  ModuleVO vo = new ModuleVO();
                  vo.setId("1");
                  vo.setNumberField(121);
                  vo.setStringField("aaa");
                  localDAO.addLocal(localVO); //This is always persisted. @Transactional is having no effect.
                  throw new Exception("test");
              }
              
              
              

               

              So I think the problem is with my datasource definition itself. How to integrate the TransactionalDriver mentioned by Michael in this configuration?

              • 4. Re: Narayana JTS with Spring in Tomee
                shabin8780

                Hi Michael,

                 

                Do you mean to say I have to define another datasource and not the one I have defined in the Resource tag?

                I have seen the jts remotebank trailmap ( quickstart/ArjunaJTS/trailmap/src/main/java/com/arjuna/demo/jts/remotebank at master · jbosstm/quickstart · GitHub ) but don't know how to use a similar setup with spring.

                • 5. Re: Narayana JTS with Spring in Tomee
                  tomjenkinson

                  Hi Shabin,

                   

                  Please can you share your project on github so I can see what is missing but you more than likely need at least a minimal jbossts-properties.xml in your classpath?

                   

                  Mike is right, in standalone mode we normally recommend transactional driver. That being said its possible Spring provides its own JCA-like facility as well to enlist the resources. I think zhfeng might be able to help us here as he is working on [JBTM-855] Create an example showing integration with Spring - JBoss Issue Tracker which would provide the Narayana transaction manager to spring.

                   

                  Thanks,

                  Tom

                  • 6. Re: Narayana JTS with Spring in Tomee
                    tomjenkinson

                    Also, there is a PR open for that one JBTM-855 Update to add the jta spring example by zhfeng · Pull Request #148 · jbosstm/quickstart · GitHub but its not ready for merge yet so shouldn't be relied upon.

                    • 7. Re: Narayana JTS with Spring in Tomee
                      zhfeng

                      Hi Shabin,

                       

                      You can take a look at the spring configuration https://github.com/zhfeng/quickstart/blob/JBTM-855/spring/jta/src/test/resources/spring-context.xml

                      The DataSource config looks like

                      <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
                              <property name="driverClassName">
                                  <value>com.arjuna.ats.jdbc.TransactionalDriver</value>
                              </property>
                              <property name="connectionProperties">
                                  <props>
                                      <prop key="user">sa</prop>
                                      <prop key="password"></prop>
                                      <prop key="DYNAMIC_CLASS">org.jboss.narayana.quickstart.spring.config.H2DataSource</prop>
                                  </props>
                              </property>
                              <property name="url" value="jdbc:arjuna:h2:mem:test"/>
                      </bean>
                      

                       

                      and you need to create a class

                      public class H2DataSource implements DynamicClass {
                          @Override
                          public XADataSource getDataSource(String dbName) throws SQLException {
                              JdbcDataSource ds = new JdbcDataSource();
                              ds.setURL("jdbc:h2:mem:test;MODE=Oracle;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
                              ds.setUser("sa");
                              ds.setPassword("");
                      
                      
                              return ds;
                          }
                      }
                      
                      
                      
                      • 8. Re: Narayana JTS with Spring in Tomee
                        shabin8780

                        Hi Amos,

                         

                        Thanks for the configuration. Using TransactionalDriver I was able to make jta work. Thanks tomjenkinson and mmusgrov for the suggestions.

                        As I was using jndi, I had to set the jtaManaged property in my Resource to false and added the datasource configuration using  TransactionalDriver and there I referenced the jndi resource. This is my config which finally made it work.

                         

                        Resource in context.xml

                        <Resource name="jdbc/NGADataSourceAppln" auth="Container"
                          type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000"
                          description="Newgen sample application" username="app"
                          password="a" driverClassName="org.apache.derby.jdbc.ClientXADataSource" JtaManaged="false" databaseName="GEMSDB"
                          url="jdbc:derby://localhost:1527/GEMSDB;create=true" />
                        

                         

                        Datasource config as spring bean

                        <bean id="dataSource1"
                          class="org.springframework.jdbc.datasource.DriverManagerDataSource">
                          <property name="driverClassName">
                          <value>com.arjuna.ats.jdbc.TransactionalDriver</value>
                          </property>
                          <property name="url" value="jdbc:arjuna:java:comp/env/jdbc/NGADataSourceAppln" />
                          <property name="username" value="app" />
                          <property name="password" value="a" />
                         </bean>
                        

                         

                        As single instance multi-datasource jta is working fine, I am moving on to try jts across multiple instances. As we already have spring remoting over rmi in our application, we were hoping we could make this work using spring remoting over rmi-iiop. Am I right in thinking that way?
                        Is there any suggestions/examples from your part on how to integrate spring remoting with iiop so that jts will work?

                        Also can we continue this discussion here?

                        • 9. Re: Narayana JTS with Spring in Tomee
                          tomjenkinson

                          I think its fine to continue the discussion here as it still relates to the title.

                           

                          It sounds like it _may_ be possible to work with the Spring remoting stuff, I honestly don't know as we haven't tried it yet as a team. What you will need to do is make sure you have a jbossts-properties.xml configured with the interceptors for the ORB that Spring is using. There is an example one (don't forget to rename it) in the download distribution: Downloads · Narayana I have raised a Jira to include some sample property files in the docs part of our site for ease of use in future: [JBTM-2510] Provide some example jbossts-properties.xml on the narayana.io site - JBoss Issue Tracker

                          • 10. Re: Narayana JTS with Spring in Tomee
                            shabin8780

                            Hi Tom,

                             

                            So I continued with my research and using spring rmi remoting and taking ideas from the trailmap I made jts in multiple instances work. But I am not sure whether it is the correct approach or not. In the client, I took the org.omg.CosTransactions.Control object from the current transaction(OTSManager.get_current()), converted it to IOR string and passed to the server using spring rmi. At the server side, I converted the string back to Control object and called OTSManager.get_current().resume() method passing the control. That approach seems to work. But as this is an explicit way of control propagation, I don't know what more need to be done(like suspend etc..). Can you please check and give some pointers.

                            This is my code and configs:

                             

                            Client

                            bean

                            <bean id="helloService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
                              <property name="serviceUrl" value="rmi://localhost:2222/helloWorldService" />
                              <property name="serviceInterface"
                              value="com.test.remote.IRemote" />
                             </bean>
                            
                            

                             

                             

                            Calling code

                            @Autowired
                             private IRemote helloService;
                            public void callingMethod(){
                                 ORB myORB = com.arjuna.orbportability.ORB.getInstance("ClientSide");
                                 Control controlObj = OTSManager.get_current().get_control();
                            
                                 String control = myORB.orb().object_to_string(controlObj);
                            
                                 System.out.println(helloService.getMsg(control));
                            }
                            

                             

                            Server

                            Spring bean

                            <bean class="org.springframework.remoting.rmi.RmiServiceExporter">
                              <property name="serviceName" value="helloWorldService" />
                              <property name="service" ref="helloWorldService" />
                              <property name="serviceInterface"
                              value="com.test.remote.IRemote" />
                              <property name="registryPort" value="2222" />
                            </bean>
                            

                             

                            Interface

                            public interface IRemote {
                              public String getMsg(String control);
                            }
                            

                             

                            Implementation

                            public class RemoteImpl implements IRemote {
                                @Autowired
                                RemoteService service; //service interface having mandatory transactional method
                                @Override
                                public String getMsg(String control) {
                                      ORB myORB = com.arjuna.orbportability.ORB.getInstance("ServerSide");
                                      Control controlObj = ControlHelper.narrow(myORB.orb().string_to_object(control));
                                      OTSManager.get_current().resume(controlObj);
                                      service.invokeService("test"); //method with @Transactional set as mandatory
                                      return "success";
                                }
                            }
                            

                             

                            So our idea is to explicitly transfer Control object and make use of jts.

                            • 11. Re: Narayana JTS with Spring in Tomee
                              tomjenkinson

                              Hi Shabin,

                               

                              If you want implicit propagation, are the interceptors being registered with the ORB? Which ORB is used for Spring?

                               

                              Thanks,

                              Tom

                              • 12. Re: Narayana JTS with Spring in Tomee
                                shabin8780

                                In this setup, spring as such is not using any specific ORB afaik because spring is used only for RMI. The only ORB part written by me is in the setup code(as part of an initializing bean).

                                com.arjuna.orbportability.ORB myORB = com.arjuna.orbportability.ORB.getInstance("ClientSide");
                                com.arjuna.orbportability.RootOA myOA = com.arjuna.orbportability.OA.getRootOA(myORB);
                                myORB.initORB(new String[]{}, null);
                                myOA.initOA();
                                ORBManager.setORB(myORB);
                                ORBManager.setPOA(myOA);
                                

                                Similar for the server with name "ServerSide". This orb is used for IOR conversion and back of the Control object.

                                 

                                Initially I tried using implicit propagation using spring rmi-iiop taking clues from this book. But I had to start a separate orbd service as a name server as mentioned in the book(I couldn't find a way without starting a name server). But even after that, implicit propagation didn't happen. Maybe because I didn't register the interceptors. But I don't know what ORB interceptors are used by spring internally. Because of all these issues, I went with the explicit propagation. So is there some issue with my current explicit propagation code?

                                • 13. Re: Narayana JTS with Spring in Tomee
                                  mmusgrov

                                  tomjenkinson posted a response (Re: JBossTS distributed without container JEE) on another thread which is relevant to your question

                                  • 14. Re: Narayana JTS with Spring in Tomee
                                    shabin8780

                                    Hi Micheal and tomjenkinson,

                                     

                                    As specified in that thread, implicit propagation using spring rmi iiop is not clear. So we are thinking of moving on with the explicit propagation.

                                    Even though my current code using explicitly propagating Control IOR is working fine, I am not sure whether I am missing something extra. So can anyone of you please tell me whether I am right in propagating the Control object and resuming the transaction it in the server side using Current and Control. If not, please tell me what more should I do.

                                    1 2 Previous Next