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 Portal 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. You can also use your own resources as participates in global transaction. By default JTA is disabled as not all databases support XA datasources and also it may have some small performance penalty as more coordination is required among resources in global transaction.
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 Portal on JBoss 7 (or EAP 6) .
-
JDBC driver - For using JTA you may need to use more production ready database, then default H2 . So you would need JDBC driver for your database. For MySQL database you can download it from http://dev.mysql.com/downloads/connector/j/ and setup it as JBoss core module as described in documentation https://access.redhat.com/site/documentation/en-US/JBoss_Enterprise_Application_Platform/6.3/html/Administration_and_Configuration_Guide/Install_a_JDBC_Driver_as_a_Core_Module1.html
-
Datasources - There are some changes needed for datasource configurations if you want JTA support. You have two possibilities how to configure datasources:
-
Configure both IDM and JCR to share same datasource. To do this, you will need to edit file GATEIN_HOME/standalone/configuration/standalone.xml and comment datasource java:/jdbcjcr_portal and configure java:jdbcidm_portal to use MySQL database (replace with DB properties according your environment):
<datasource jndi-name="java:/jdbcidm_portal" pool-name="IDMPortalDS" enabled="true" use-java-context="true">
<connection-url>jdbc:mysql://localhost/portal</connection-url>
<driver>mysql</driver>
<security>
<user-name>portal</user-name>
<password>portal</password>
</security>
<pool>
<min-pool-size>10</min-pool-size>
<max-pool-size>100</max-pool-size>
<prefill>true</prefill>
</pool>
</datasource>
<!--<datasource jndi-name="java:/jdbcjcr_portal" pool-name="JCRPortalDS" enabled="true" use-java-context="true">
<connection-url>jdbc:h2:file:${jboss.server.data.dir}/gatein/portal/jdbcjcr_portal;DB_CLOSE_DELAY=-1</connection-url>
<driver>h2</driver>
<security>
<user-name>sa</user-name>
<password>sa</password>
</security>
</datasource>-->
You should also add MySQL module into drivers as described in JBoss7/EAP6 documentation:
<driver name="mysql" module="com.mysql">
<xa-datasource-class>com.mysql.jdbc.Driver</xa-datasource-class>
</driver>
You also need to edit GATEIN_HOME/standalone/configuration/gatein/configuration.properties and ensure that property gatein.jcr.datasource.name has value java:/jdbcidm, which means that it will use IDM datasource. You can check that also property gatein.idm.datasource.name is using IDM datasource, but it should use it by default (no change needed):
gatein.jcr.datasource.name=java:/jdbcidm
gatein.idm.datasource.name=java:/jdbcidm
This will cause that both IDM and JCR will share same datasource . Thing is that this is non-XA datasource and so it 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 no-XA datasource is supported by all DB types (including H2). But it also has some limitations. For example, you can't use different no-XA datasource for your own portlet applications, which are accessing DB.
-
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 have 2 separate XA datasources. So configuration of portal datasources in GATEIN_HOME/standalone/configuration/standalone.xml can look like this:
<xa-datasource jndi-name="java:/jdbcidm_portal" pool-name="IDMPortalDS" enabled="true" use-java-context="true">
<xa-datasource-property name="ServerName">localhost</xa-datasource-property>
<xa-datasource-property name="DatabaseName">portalidm</xa-datasource-property>
<driver>mysql</driver>
<xa-pool>
<min-pool-size>10</min-pool-size>
<max-pool-size>100</max-pool-size>
<prefill>true</prefill>
</xa-pool>
<security>
<user-name>portal</user-name>
<password>portal</password>
</security>
</xa-datasource>
<xa-datasource jndi-name="java:/jdbcjcr_portal" pool-name="JCRPortalDS" enabled="true" use-java-context="true">
<xa-datasource-property name="ServerName">localhost</xa-datasource-property>
<xa-datasource-property name="DatabaseName">portaljcr</xa-datasource-property>
<driver>mysql</driver>
<xa-pool>
<min-pool-size>10</min-pool-size>
<max-pool-size>100</max-pool-size>
<prefill>true</prefill>
</xa-pool>
<security>
<user-name>portal</user-name>
<password>portal</password>
</security>
</xa-datasource>
and configuration of driver like this:
<driver name="mysql" module="com.mysql">
<xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class>
</driver>
In GATEIN_HOME/standalone/configuration/gatein/configuration.properties are default values, so names of datasources are like this:
gatein.jcr.datasource.name=java:/jdbcjcr
gatein.idm.datasource.name=java:/jdbcidm
Note that for separate datasources, you will need to use 2 separate databases. Like MySQL databases "portalidm" and "portaljcr" from previous example. For some databases like Sybase, you even need to make sure that databases are not using same DB process, ideally they are on different hosts. If both datasources are using same database, it may not work due to the fact that each datasource is separate XA resource and hence there will be an attempt to enlist 2 XA resources to same database with same transaction, which will fail in most cases.
So if you have just 1 database and want to use JTA, you need to use shared datasource for both IDM and JCR. Note that it's better to use XA datasource if supported by your database as you won't have "Last resource" limitation mentioned in previous section.
-
Hibernate configuration - You need to configure Hibernate to use JTA. In file GATEIN_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/organization/idm-configuration.xml you need to change/comment property of HibernateService :
<!-- Non-JTA setup -->
<!--<property name="hibernate.current_session_context_class" value="thread"/>-->
and instead add/uncomment those properties:
<!-- JTA setup -->
<property name="hibernate.current_session_context_class" value="jta"/>
<property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory" />
<property name="hibernate.transaction.jta.platform" value="org.exoplatform.services.organization.idm.UserTransactionJtaPlatform" />
-
useJTA switch - In the same file, you need to change property useJTA of OrganizationService . It 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.
-
lazyStartOfHibernateTransaction switch - In the file GATEIN_HOME/gatein/gatein.ear/portal.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 no-XA 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 2.b) or you will need to reuse same datasource as GateIn Portal is using (See section 2.a ).
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.