3 Replies Latest reply on Nov 17, 2014 2:41 AM by Horia Chiorean

    Using modeshape with other JTA transaction

    Son Nguyen Newbie

      Hi all!

      I have an application that using spring & modeshape, running in tomcat server. It's using jboss jta to manage jta transaction.

      I want store data in my own database & also in modeshape store. But when my code use JTA transaction, it throws exception that:

      javax.transaction.NotSupportedException: BaseTransaction.checkTransactionState - ARJUNA016051: thread is already associated with a transaction!

      I'm using spring 3.1, modeshape 3.6.0Final, jboss jta 4.14.0

      Here is my source code & cofiguration.

      Thanks for helping

       

      // source code

      @Transactional(value = "XA_TRANSACTION", rollbackFor = {Exception.class}) 
      public void doUpdate({
      // Code insert data to my db
      // Code insert data to modeshape
      }
      

       

      <bean id="jndiExporterForModeshape" class="mypackage.JndiExporter">
        <property name="jndiMapping">
        <map>
       <entry key="JNDIDatasource" value-ref="myXADatasource" />
        </map>
        </property>
        </bean>
      

       

      // spring datasource config

      <bean id="myXADatasource" class="org.apache.commons.dbcp.managed.BasicManagedDataSource"
        destroy-method="close">
        <property name="transactionManager" ref="jbossTransactionManager" />
        <property name="url" value="${database_com.url}" />
        <property name="username" value="${database_com.username}" />
        <property name="password" value="${database_com.password}" />
        <property name="driverClassName" value="${database_com.driver}" />
        <property name="maxActive" value="${database_xa.pool.max}" />
        <property name="testWhileIdle" value="true" />
        <property name="validationQuery" value="select 1" />
        </bean>
      

       

      // jta transaction config

      <bean id="jbossTransactionManager"
        class="com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple">
        </bean>
      
      
        <bean id="myJtaTransactionManager"
        class="org.springframework.transaction.jta.JtaTransactionManager">
        <property name="transactionManager" ref="jbossTransactionManager" />
        <property name="defaultTimeout" value="500"></property>
        </bean>
      
        <tx:annotation-driven transaction-manager="myJtaTransactionManager"
        proxy-target-class="true" />
      

       

       

      // repository config

      {
          "name" : "MYREPO",
          "transactionMode" : "auto",
          "monitoring" : {
              "enabled" : true,
          },
          "workspaces" : {
              "predefined" : ["DataStore", "FileStore", "Security"],
              "default" : "DataStore",
              "allowCreation" : true,
          },
          "storage" : {
              "cacheName" : "repo",
              "cacheConfiguration" : "repository/infinispan/cache-config.xml",
              "transactionManagerLookup" = "mypackage.transaction.JbossTSStandaloneTransactionManagerLookup",
              "binaryStorage" : {
                  "type" : "cache",
                  "dataCacheName" : "data",
                  "metadataCacheName" : "metadata",
                  "cacheConfiguration" : "repository/infinispan/store-config.xml",
                  "minimumBinarySizeInBytes" : 4096,
                  "description" : ""
              }
          },
          "security" : {
             
              "providers" : [
                  {
                      "name" : "Spring jcr Authentication Provider",
                      "classname" : "mypackage.security.provider.AppBasedSpringJcrAuthenticationProvider",
                  }
              ]
          },
          "query" : {
              "enabled" : true,
              "textExtracting": {
                  "threadPool" : "test",
                  "extractors" : {
                      "tikaExtractor":{
                          "name" : "General content-based extractor",
                          "classname" : "tika",
                      }
                  }
               },
              "indexStorage" : {
                  "type" : "filesystem",
                  "location" : "${modeshape_config_index_storage}",
                  "lockingStrategy" : "native",
                  "fileSystemAccessType" : "auto"
              },
              "indexing" : {
                  "threadPool" : "modeshape-workers",
                  "analyzer" : "org.apache.lucene.analysis.standard.StandardAnalyzer",
                  "similarity" : "org.apache.lucene.search.DefaultSimilarity",
                  "batchSize" : -1,
                  "indexFormat" : "LUCENE_35",
                  "readerStrategy" : "shared",
                  "mode" : "sync",
                  "asyncThreadPoolSize" : 1,
                  "asyncMaxQueueSize" : 50,
                  "backend" : {
                      "type" : "lucene",
                       
                  },
                  "rebuildOnStartup" : {
                  "when" : "always",
                  "includeSystemContent" : true,
                  "mode" : "SYNC"
                  },
                  "hibernate.search.custom.overridden.property" : "value",
              }
          },
          "sequencing" : {
              "removeDerivedContentWithOriginal" : true,
              "threadPool" : "modeshape-workers",
              "sequencers" : {
                  "ZIP Sequencer" : {
                      "description" : "ZIP Files loaded under '/files' and extracted into '/sequenced/zip/$1'",
                      "classname" : "ZipSequencer",
                      "pathExpressions" : ["default:/files(//)(*.zip[*])/jcr:content[@jcr:data] => default:/sequenced/zip/$1"],
                  },
                  "Delimited Text File Sequencer" : {
                      "classname" : "org.modeshape.sequencer.text.DelimitedTextSequencer",
                      "pathExpressions" : [ 
                          "default:/files//(*.csv[*])/jcr:content[@jcr:data] => default:/sequenced/text/delimited/$1"
                      ],
                      "splitPattern" : ","
                  }
              }
          },
          
          "node-types" : [
          ]
      }
      

       

      // cache config

      <namedCache name="repo">
             <transaction transactionManagerLookupClass="mypackage.transaction.JbossTSStandaloneTransactionManagerLookup"
                          transactionMode="TRANSACTIONAL"
                          lockingMode="PESSIMISTIC"/>
             <loaders passivation="false" shared="false" preload="false">
      
                <loader class="org.infinispan.loaders.jdbc.binary.JdbcBinaryCacheStore"
                        fetchPersistentState="false"
                        purgeOnStartup="false">
                   <properties>
                      <property name="cacheName" value="repo"/>
                      <property name="bucketTableNamePrefix" value="qmtb" />
                      <property name="idColumnName" value="ID"/>
                      <property name="dataColumnName" value="DATA"/>
                      <property name="timestampColumnName" value="TIMESTAMP"/>
                      <property name="timestampColumnType" value="bigint"/>
                      <property name="idColumnType" value="character varying(255)"/>
                      <property name="dataColumnType" value="bytea"/>
                      <property name="connectionFactoryClass" value="org.infinispan.loaders.jdbc.connectionfactory.ManagedConnectionFactory" />
                      <property name="datasourceJndiLocation" value="JNDIDatasource"/>
                   </properties>
                </loader>
             </loaders>
          </namedCache>
      

       

       

      // transaction manager lookup class

      public class JbossTSStandaloneTransactionManagerLookup implements
        TransactionManagerLookup {
      
      
        private TransactionManager getTransactionManager(Properties props) throws HibernateException {
        try {
        //Call com.arjuna.ats.jta.TransactionManager.transactionManager
        Class<?> jbossTransactionManagerClass = Class.forName( "com.arjuna.ats.jta.TransactionManager" );
        final Method getTransactionManagerMethod = jbossTransactionManagerClass.getMethod( "transactionManager" );
        //static method call
        return (TransactionManager) getTransactionManagerMethod.invoke( null );
        }
        catch ( Exception e ) {
        throw new HibernateException( "Could not obtain JBoss Transactions transaction manager instance", e );
        }
        }
      
        @Override
        public TransactionManager getTransactionManager() throws Exception {
        return getTransactionManager(null);
        }
      }
      
        • 1. Re: Using modeshape with other JTA transaction
          Horia Chiorean Master

          First, please try to use one of the latest ModeShape versions (ideally 4.0 with Infinispan 6) or if not 3.8.1.Final

          Second, the only thing I can suggest except debugging your local code is making sure that when using Spring's @Transactional (like your bean does) will actually use at runtime *the same transaction manager/tx instance* as the one that's returned by the JbossTSStandaloneTransactionManagerLookup for Infinispan. Looking at your code I'm not sure that's the case since your using Class.forName & getMethod

          You should look at modeshape-examples/modeshape-spring-example at master · ModeShape/modeshape-examples · GitHub where we're using Spring & Atomikos JTA and our TransactionManagerLookup class get the tx manager injected by Spring (making sure it's the same instance).

          • 2. Re: Re: Using modeshape with other JTA transaction
            Son Nguyen Newbie

            Hi

            Thank for your answer. I had updated to modeshap 4.0 with infinispan 6, use atomikos jta transaction like your example but it's now timeout and don't throws any exception.

            I'd googled and someone said that set useLockStriping property in infinispan lock config to false, but still not success .

            I debug into code, it stuck at session.save(); line. And console log thows an exception periodically:

            DEBUG: org.infinispan.marshall.core.VersionAwareMarshaller - Object is not serializable

            java.io.NotSerializableException: org.infinispan.persistence.support.Bucket

             

            Here is my new configuration:

            <default>
                   <locking concurrencyLevel="100" isolationLevel="READ_COMMITTED" useLockStriping="false"/>
                </default>
               
                <namedCache name="repo">
                <transaction transactionManagerLookupClass="mypackage.AtomikosTransactionManagerLookup"
                transactionMode="TRANSACTIONAL"
                lockingMode="PESSIMISTIC">
                </transaction>
                <persistence passivation="false">
                <jdbc:binaryKeyedJdbcStore>
                <jdbc:binaryKeyedTable prefix="qmtb" createOnStart="true">
                <jdbc:idColumn name="ID" type="character varying(255)"/>
                <jdbc:dataColumn name="DATA" type="bytea"/>
                <jdbc:timestampColumn name="TIMESTAMP" type="bigint"/>
                </jdbc:binaryKeyedTable>
                <jdbc:dataSource jndiUrl="JNDIDatasource"/>
                </jdbc:binaryKeyedJdbcStore>
                </persistence>
                </namedCache>
            
            

             

            {
                "name" : "MYREPO",
                "transactionMode" : "auto",
                "monitoring" : {
                    "enabled" : true,
                },
                "workspaces" : {
                    "predefined" : ["DataStore", "FileStore", "Security"],
                    "default" : "DataStore",
                    "allowCreation" : true,
                },
                "storage" : {
                    "cacheName" : "repo",
                    "cacheConfiguration" : "repository/infinispan/cache-config.xml",
                    "binaryStorage" : {
                        "type" : "cache",
                        "dataCacheName" : "data",
                        "metadataCacheName" : "metadata",
                        "cacheConfiguration" : "repository/infinispan/store-config.xml",
                        "minimumBinarySizeInBytes" : 4096
                    }
                },
                "security" : {
                  
                    "providers" : [
                        {
                            "name" : "Spring jcr Authentication Provider",
                            "classname" : "mypackage.AppBasedSpringJcrAuthenticationProvider",
                        }
                    ]
                },
                "indexProviders" : {
                    "local" : {
                        "classname" : "org.modeshape.jcr.index.local.LocalIndexProvider",
                        "directory" : "${modeshape_config_index_storage}"
                    },
                },
                "indexes" : {      
                    "nodesByName" : {
                        "kind" : "value",
                        "provider" : "local",
                        "nodeType" : "nt:base",
                        "columns" : "jcr:name(NAME)"
                    },
                    "nodesByLocalName" : {
                        "kind" : "value",
                        "provider" : "local",
                        "nodeType" : "nt:base",
                        "columns" : "mode:localName(STRING)"
                    },
                    "nodesByDepth" : {
                        "kind" : "value",
                        "provider" : "local",
                        "nodeType" : "nt:base",
                        "columns" : "mode:depth(LONG)"
                    },
                    "nodesByPath" : {
                        "kind" : "value",
                        "provider" : "local",
                        "nodeType" : "nt:base",
                        "columns" : "jcr:path(PATH)"
                    }
                 },
                "sequencing" : {
                    "removeDerivedContentWithOriginal" : true,
                    "threadPool" : "modeshape-workers",
                    "sequencers" : {
                        "ZIP Sequencer" : {
                            "description" : "ZIP Files loaded under '/files' and extracted into '/sequenced/zip/$1'",
                            "classname" : "ZipSequencer",
                            "pathExpressions" : ["default:/files(//)(*.zip[*])/jcr:content[@jcr:data] => default:/sequenced/zip/$1"],
                        },
                        "Delimited Text File Sequencer" : {
                            "classname" : "org.modeshape.sequencer.text.DelimitedTextSequencer",
                            "pathExpressions" : [
                                "default:/files//(*.csv[*])/jcr:content[@jcr:data] => default:/sequenced/text/delimited/$1"
                            ],
                            "splitPattern" : ","
                        }
                    }
                },
               
                "node-types" : [
                ]
            }
            
            

             

            Is my configuration wrong?

            Thanks.

            • 3. Re: Re: Using modeshape with other JTA transaction
              Horia Chiorean Master

              The configuration looks fine. You should debug your application (and make sure your classpath is correct. For example, if you moved to Atomikos make sure these artifacts are in you classpath. Also, when using string-based jdbc cachestore embedded with a JNDI DS, make sure you're using a connection factory library - for example C3P0 etc)