Blog

« Voltar

Demoiselle 2 + two-phase commit no Tomcat 6

Olá a todos, meu nome é Danilo Viana, trabalho no Serpro-SSA e este é meu primeiro post contribuindo para o Demoiselle. No momento estou participando de um projeto utilizando Demoiselle 2, Hibernate e two-phase commit, ou seja, precisariamos sincronizar acesso a dois bancos de dados em uma única transação.

Surgiu a possibilidade de nosso projeto não poder utilizar JBoss 6, que possui suporte nativo a two-phase commit através da API XATransaction. Ao invés disso o projeto passaria a executar em Tomcat 6, sem o mesmo suporte nativo. Com o projeto já bastante adiantado e sem possibilidade de voltar atrás em nossa decisão de tecnologia, foi necessário configurar o Tomcat 6 para ter suporte ao Demoiselle 2 utilizando JTA e two-phase commit.

Suporte a JSF 2

O primeiro problema que encontramos foi a implementação da Expression Language utilizada pelo Tomcat 6. No JSF 2 as expressões em EL suportam chamada de métodos com parâmetros mas esse suporte não está presente na biblioteca do Tomcat. Testamos a versão utilizada no Glassfish (disponível no repositório Maven http://download.java.net/maven/glassfish sob o group-id “el-impl”) que funcionou sem problemas.

Baixe via Maven ou acessando o repositório no browser, os arquivos “el-api.jar” e “el-impl.jar”, acesse a pasta [TOMCAT 6]\lib e copie estes arquivos lá, substituindo o arquivo el-api.jar já existente (faça um backup do arquivo original).

Além disso é necessário ensinar o Tomcat a fabricar o objeto que processa instruções EL. Para isso no arquivo “web.xml” do seu projeto web adicione o parâmetro abaixo:

1
2
3
4
<context-param>
    <param-name>com.sun.faces.expressionFactory</param-name>
    <param-value>com.sun.el.ExpressionFactoryImpl</param-value>
</context-param>

Habilitando two-phase commit

O Tomcat não tem suporte nativo a api XATransaction, que provê suporte a two-phase commit. Para ter este suporte vamos utilizar o framework Atomikos (http://www.atomikos.com), que é livre e está sob licença Apache 2.0

O Atomikos está no repositório geral Maven, então basta acrescentar em seu projeto a dependência à biblioteca “transactions-hibernate3″, que está no group-id “com.atomikos” e seu projeto já poderá utilizar two-phase commit no JPA com Hibernate como persistence provider.

É necessário copiar em seu projeto uma classe que substitui o ObjectFactory original do Tomcat 6, do contrário seu projeto não será capaz de obter instâncias de UserTransaction já que o Tomcat 6 não tem suporte a fornecer objetos dessa classe. Acesse este link do site do Atomikos e copie a classe ou o jar disponibilizado para seu projeto.

Agora para configurar o acesso à conexão. Este é um exemplo de criação de recurso JNDI no arquivo “context.xml”, onde criamos tanto o recurso de acesso à conexões quanto o recurso de acesso à transações via UserTransaction. Note o parâmetro “factory”, que referencia a classe copiada no passo anterior. Note também que estamos utilizando o PostgreSQL como exemplo, pois esse SGBP suporta transações XA, verifique se seu SGBD oferece este suporte.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<Context>
    <Resource
        name="jdbc/nome_datasource"
        auth="Container"
        type="com.atomikos.jdbc.AtomikosDataSourceBean"
        factory="com.atomikos.tomcat.BeanFactory"
        uniqueResourceName="jdbc/nome_datasource"
        xaDataSourceClassName="org.postgresql.xa.PGXADataSource"
        xaProperties.databaseName="base_principal"
        xaProperties.serverName="ip_servidor_banco_principal"
        xaProperties.user="****"
        xaProperties.password="****"
        maxPoolSize="20"
    />
 
    <Resource
        name="UserTransaction" auth="Container"
        type="javax.transaction.UserTransaction"
        factory="com.atomikos.icatch.jta.UserTransactionFactory"
    />
</Context>

Utilizando JTA e Hibernate como persistence provider, é necessário incluir os seguintes parâmetros no arquivo “persistence.xml”:

1
2
3
4
5
6
7
8
<persistence-unit name="unidade_persistencia">
    <jta-data-source>java:comp/env/jdbc/nome_datasource</jta-data-source>
    <properties>
        <!--...-->
        <property name="hibernate.transaction.manager_lookup_class" value="com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup" />
        <!--...-->
    </properties>
</persistence-unit>

Caso esteja utilizando Hibernate nativo, sem o JTA, estas configurações devem estar presentes em seu arquivo “hibernate.cfg.xml”:

1
2
3
4
<property name="hibernate.connection.datasource">java:comp/env/jdbc/nome_datasource</property>
<property name="hibernate.transaction.manager_lookup_class">com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup</property>
<property name="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property>
<property name="jta.UserTransaction">java:comp/env/UserTransaction</property>

Por último, o Demoiselle 2 não está preparado para produzir instâncias de UserTransaction para Tomcat 6, então por ora é necessário acrescentar ao seu projeto um produtor deUserTransaction através da anotação @Produces.

Crie a classe abaixo em seu projeto, o pacote não é importante, mas note a anotação @Produces, ela vai indicar ao CDI que esta classe é responsável por produzir instâncias deUserTransaction.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.tomcat6.usertransactionsupport;
 
import javax.enterprise.inject.Produces;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.transaction.UserTransaction;
 
/**
* Classe responsável por produzir UserTransactions no Tomcat 6, pois
* o Demoiselle 2 não produz estas classes normalmente em um ambiente Tomcat.
*/
public class TomcatUserTransactionProducer {
 
@Produces
public UserTransaction create() {
UserTransaction transaction = null;
 
try {
Context context = new InitialContext();
transaction = (UserTransaction) context.lookup("java:comp/env/UserTransaction");
} catch (NamingException e) {
e.printStackTrace();
}
 
return transaction;
}
 
}

Conclusão

Com esses passos você será capaz de utilizar JSF 2 e two-phase commit no Tomcat 6. Se você está desenvolvendo um sistema com estes requisitos mas não pode utilizar um container com suporte nativo a estas funcionalidades, ou acredita que o JBoss é muito pesado e seu projeto simples não necessita de tanto, esta solução pode ser o que você procura.

Autor: Dancovich

Anterior
Comentários