JTA integration with GateIn

Version 8

    WARN: THIS WIKI WORKS JUST FOR OLDER GATEIN VERSIONS DEPLOYED ON JBOSS 5 (OR EPP 5.2). FOR NEW INSTRUCTIONS WITH GATEIN ON JBOSS 7 (JPP6), YOU CAN TAKE A LOOK AT THE OFFICIAL GATEIN DOCUMENTATION JTA integration - GateIn Portal 3.8 - Project Documentation Editor .


    Note: This configuration process can be applied in GateIn since version 3.2.0.Final (JBoss EPP 5.2.0).

     

    GateIn portal stores it's data in two persistent storages. First storage is IDM database, which is used for identity related data (users, groups and their memberships). Second is JCR, which is used to store all other data (pages, navigations, application registry and everything else). So GateIn is using separate datasource for IDM and separate for JCR.

     

    In some cases, it may be useful to configure GateIn portal to support JTA . In this case will be each HTTP request to portal encapsulated in JTA transaction. This may be sometimes useful as access to both datasources and other resources will be managed inside this global transaction. It may be good for performance reasons, because normally when access to GateIn portal is not managed within JTA transaction, then request is encapsulated within Hibernate transaction (Hibernate framework is used by Picketlink IDM to read data from DB). And in this case is DB connection always obtained from DB connection pool during startup of Hibernate transaction.

     

    JTA can be useful to improve this situation, as access to DB connections is managed and connection is obtained only when is needed by application. This means that you won't need so many connections from DB connection pool and you will be able to handle bigger number of concurrent users with your portal.

     

    How to enable JTA support

     

    In this example, we will configure GateIn portal for using JTA and MySQL database to access persistent data. We assume that you are using GateIn on JBoss 5 (Some steps may be slightly different with different servers)

     

     

    1. JDBC driver - For using JTA you may need to use more production ready database, then default HSQLDB. So if not using HSQLDB, you would need JDBC driver for your database. For MySQL database you can download it from http://dev.mysql.com/downloads/connector/j/ and add downloaded JAR file into GATEIN_HOME/server/default/lib/ directory.

     

     

    2. JCR configuration

    You need to configure JCR to indicate that DB connections needed by eXo JCR will be managed within JTA transaction. This can be done by adding special configuration section with DataSourceProvider into file JBOSS_HOME/server/default/deploy/gatein.ear/02portal.war/WEB-INF/conf/jcr/jcr-configuration.xml

     

      <component>
        <key>org.exoplatform.services.jdbc.DataSourceProvider</key>
        <type>org.exoplatform.services.jdbc.impl.DataSourceProviderImpl</type>
        <init-params>
          <value-param>
            <name>always-managed</name>
            <value>true</value>
          </value-param>
        </init-params>
      </component>
    

    Refer to JCR docs for more info<http://docs.jboss.org/exojcr/1.14.6-GA/developer/en-US/html_single/#Kernel.DataSourceProvider>

     

    Note: This step is not needed if you're using JBoss EPP 5.2 or above. Because in EPP is DataSourceProvider configured by default.

     

     

    3. Datasources - With it's default setup is GateIn using Apache DBCP datasources, which are automatically initialized and bound to JNDI if no other datasource is explicitly configured. To have JTA support, we need to override default datasources and use JBoss JCA datasources, which are manageable by JTA transaction. You have two possibilities how to configure datasources.

     

    a) Create file GATEIN_HOME/server/default/deploy/gatein-ds.xml and add this content to this file (Configure DB connection properties according to your DB environment):

     

     

    <datasources>
    
      <local-tx-datasource>
        <jndi-name>jdbcidm</jndi-name>   
        <connection-url>jdbc:mysql://localhost/jboss_portal7</connection-url>
        <driver-class>com.mysql.jdbc.Driver</driver-class>
        <user-name>jboss_portal</user-name>
        <password>password</password>
        <min-pool-size>10</min-pool-size>
        <max-pool-size>20</max-pool-size>
        <prepared-statement-cache-size>32</prepared-statement-cache-size>
      </local-tx-datasource>
    
    </datasources>
    

     

    You need to configure both IDM and JCR to this datasource in JBOSS_HOME/server/default/conf/gatein/configuration.properties . So properties with datasource names should be like this:

     

    gatein.jcr.datasource.name=java:jdbcidm
    gatein.idm.datasource.name=java:jdbcidm
    

     

    This will cause that both IDM and JCR will share same datasource of type local-tx-datasource . Thing is that local-tx-datasource does not actually support 2-phase commit and it's treated as "Last resource" in JTA transaction (See http://docs.redhat.com/docs/en-US/JBoss_Enterprise_Application_Platform/5/html/Administration_And_Configuration_Guide/lrco-overview.html for details). So you can normally use only one DS of this type within one JTA transaction. This approach has advantage that local-tx-datasource is supported by all DB types (including HSQLDB). But it also has some limitations. For example, you can't use different local-tx-datasource for your own portlet applications, which are accessing DB.

     

    b) Second approach can be used with databases, which supports "real" transactions with 2-phase commits. In this case, you don't need to share same datasource for JCR and IDM, but you can configure 2 separate datasources of type xa-datasource . So file JBOSS_HOME/server/default/deploy/gatein-ds.xml will look similarly to this:

     

    <datasources>
    
      <xa-datasource>
        <jndi-name>jdbcidm</jndi-name>
        <track-connection-by-tx>true</track-connection-by-tx>
        <xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class>
        <xa-datasource-property name="ServerName">localhost</xa-datasource-property>
        <xa-datasource-property name="DatabaseName">portal</xa-datasource-property>
        <xa-datasource-property name="User">portal</xa-datasource-property>
        <xa-datasource-property name="Password">password</xa-datasource-property>   
        <metadata>
           <type-mapping>mySQL</type-mapping>
        </metadata>
      </xa-datasource>
      <xa-datasource>
        <jndi-name>jdbcjcr</jndi-name>
        <track-connection-by-tx>true</track-connection-by-tx>
        <xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class>
        <xa-datasource-property name="ServerName">localhost</xa-datasource-property>
        <xa-datasource-property name="DatabaseName">portal</xa-datasource-property>
        <xa-datasource-property name="User">portal</xa-datasource-property>
        <xa-datasource-property name="Password">password</xa-datasource-property>   
        <metadata>
           <type-mapping>mySQL</type-mapping>
        </metadata>
      </xa-datasource>
    
    </datasources>
    

     

    And GATEIN_HOME/server/default/conf/gatein/configuration.properties can have default values, which means separate datasources for both IDM and JCR:

     

    gatein.jcr.datasource.name=java:jdbcjcr
    gatein.idm.datasource.name=java:jdbcidm
    

     

    You can look at examples how to configure xa-datasource for your database in GATEIN_HOME/docs/examples/jca/ directory. And look for files, which ends with *xa-ds.xml . You can notice that there are no

    available files for all databases. It's because some databases and JDBC drivers don't support 2-phase commits, which is needed for XA resources. Example of such database is HSQLDB bundled with JBoss by default.

     

    4. Hibernate configuration - You need to configure Hibernate to use JTA. In file GATEIN_HOME/server/default/deploy/gatein.ear/02portal.war/WEB-INF/conf/organization/idm-configuration.xml you need to change 2 properties of HibernateService :

     

    <property name="hibernate.current_session_context_class" value="jta"/>
    <property name="hibernate.connection.autocommit" value="false"/>
    

     

    And add 3 new properties for this HibernateService into the existing ones:

     

    <property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory" />
    <property name="jta.UserTransaction" value="java:comp/UserTransaction" />
    <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup" />
    

     

    5. useJTA switch - In the same file, you need to change one new property of OrganizationService . It's property useJTA which needs to be configured to true:

     

              <field name="useJTA">
                <boolean>true</boolean>
              </field>
    

    This will cause that PicketlinkIDMOrganizationServiceImpl will encapsulate each HTTP request with JTA transaction, instead of encapsulating the request within Hibernate transaction API. As pointed before, encapsulating request with Hibernate transaction API is causing that DB connection needs to be obtained immediately from connection pool and commited at the end of the request, which is not always optimal and may have performance penalties and lack of DB connections when big number of users is reaching GateIn portal concurrently.

     

    6. lazyStartOfHibernateTransaction switch - In the file GATEIN_HOME/server/default/deploy/gatein.ear/02portal.war/WEB-INF/conf/organization/picketlink-idm/picketlink-idm-config.xml you need to have this switch of HibernateIdentityStore turned to false:

     

    <option>
       <name>lazyStartOfHibernateTransaction</name>
       <value>false</value>
    </option>
    

     

    This option needs to be switched to false as we manage transactions with JTA and we don't use Picketlink IDM transaction API.

     

    Now we are done with configuration. You can try to start your GateIn portal and check if everything is working as expected.

     

    LIMITATIONS:

    As pointed before, you can have only one datasource of type local-tx-datasource to participate in JTA transaction. So if you are using this type of DS from your portlet applications, you may need to change it to xa-datasource (See section 3.b) or you will need to reuse same datasource as GateIn is using (See section 3.a ). Another possibility is to change your DS to type no-tx-datasource, which means that DB connections from this datasource won't be managed within global JTA transaction and will be independent on it.

     

    As pointed before, switching useJTA parameter to true means that whole request is wrapped in JTA transaction (Exact boundaries of global JTA transaction are methods startRequest and endRequest of class PicketlinkIDMOrganizationServiceImpl). This can mean that if you are using managed transactions from your portlet applications (like using EJB with Container-Managed Transactions), there may be some changes in behaviour of your application with respect to transactions. Especially make sure that you're not trying to start or commit JTA transactions from your portlet application.