[Resolvido] Problema com recurso XA em 2 EJBs

Olá a todos.

Estou com um problema relacionado a EJB. Eu tenho 2 EJBs, um Bancario e outro OperadoraCelular. O componete bancário deverá fazer uso do componente Operadora de celular. E aplicação cliente deve ter acesso apenas ao componente bancário.

Eu já testei os 2 módulso EJBs separadamente, e eles funcionam perfeitamente. O problema é quando eu executo a aplicação cliente na situação descrita acima, cada componente EJB possui seu banco de dados. Na situação atual o OperadoraCelular deve persistir no MySQL e o Bancario deve persistir no Derby. Já tentei no Derby, MySQL e PostgreSQL, e nada. Os 2 EJBs estão no mesmo servidor de aplicação, que é o Glassfish, o 2 bancos de dados também estão na mesma máquina.

Sempre tá dando esse problema aqui Local transaction already has 1 non-XA Resource: cannot add more resources.

Algúem sabe como posso resolver esse problema de XA para que seja possível suportar transações distribuídas?

Trecho da excessão está abaixo.

GRAVE: RAR5027:Unexpected exception in resource pooling 
java.lang.IllegalStateException: Local transaction already has 1 non-XA Resource: cannot add more resources.  
	at com.sun.enterprise.transaction.JavaEETransactionManagerSimplified.enlistResource(JavaEETransactionManagerSimplified.java:334)
	at com.sun.enterprise.resource.rm.SystemResourceManagerImpl.enlistResource(SystemResourceManagerImpl.java:103)
	at com.sun.enterprise.resource.pool.PoolManagerImpl.getResource(PoolManagerImpl.java:208)
	at com.sun.enterprise.connectors.ConnectionManagerImpl.getResource(ConnectionManagerImpl.java:338)
	at com.sun.enterprise.connectors.ConnectionManagerImpl.internalGetConnection(ConnectionManagerImpl.java:301)
	at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:190)
	at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:165)
	at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:160)
	at com.sun.gjc.spi.base.DataSource.getConnection(DataSource.java:113)
	at oracle.toplink.essentials.jndi.JNDIConnector.connect(JNDIConnector.java:145)
	at oracle.toplink.essentials.sessions.DatasourceLogin.connectToDatasource(DatasourceLogin.java:184)
	at oracle.toplink.essentials.internal.databaseaccess.DatasourceAccessor.connect(DatasourceAccessor.java:233)
	at oracle.toplink.essentials.internal.databaseaccess.DatabaseAccessor.connect(DatabaseAccessor.java:242)
	at oracle.toplink.essentials.internal.databaseaccess.DatasourceAccessor.reconnect(DatasourceAccessor.java:436)
	at oracle.toplink.essentials.internal.databaseaccess.DatabaseAccessor.reconnect(DatabaseAccessor.java:1177)
	at oracle.toplink.essentials.internal.databaseaccess.DatasourceAccessor.incrementCallCount(DatasourceAccessor.java:220)
	at oracle.toplink.essentials.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:479)
	at oracle.toplink.essentials.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:452)
	at oracle.toplink.essentials.internal.sessions.AbstractSession.executeCall(AbstractSession.java:690)
	at oracle.toplink.essentials.internal.queryframework.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:228)
	at oracle.toplink.essentials.internal.queryframework.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:214)
	at oracle.toplink.essentials.internal.queryframework.DatasourceCallQueryMechanism.insertObject(DatasourceCallQueryMechanism.java:346)
	at oracle.toplink.essentials.internal.queryframework.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:191)
	at oracle.toplink.essentials.internal.queryframework.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:205)
	at oracle.toplink.essentials.internal.queryframework.DatabaseQueryMechanism.insertObjectForWrite(DatabaseQueryMechanism.java:564)
	at oracle.toplink.essentials.queryframework.InsertObjectQuery.executeCommit(InsertObjectQuery.java:89)
	at oracle.toplink.essentials.internal.queryframework.DatabaseQueryMechanism.performUserDefinedWrite(DatabaseQueryMechanism.java:750)
	at oracle.toplink.essentials.internal.queryframework.DatabaseQueryMechanism.performUserDefinedInsert(DatabaseQueryMechanism.java:714)
	at oracle.toplink.essentials.internal.queryframework.DatabaseQueryMechanism.insertObjectForWriteWithChangeSet(DatabaseQueryMechanism.java:602)
	at oracle.toplink.essentials.queryframework.WriteObjectQuery.executeCommitWithChangeSet(WriteObjectQuery.java:162)
	at oracle.toplink.essentials.internal.queryframework.DatabaseQueryMechanism.executeWriteWithChangeSet(DatabaseQueryMechanism.java:390)
	at oracle.toplink.essentials.queryframework.WriteObjectQuery.executeDatabaseQuery(WriteObjectQuery.java:109)
	at oracle.toplink.essentials.queryframework.DatabaseQuery.execute(DatabaseQuery.java:628)
	at oracle.toplink.essentials.queryframework.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:555)
	at oracle.toplink.essentials.queryframework.ObjectLevelModifyQuery.executeInUnitOfWorkObjectLevelModifyQuery(ObjectLevelModifyQuery.java:138)
	at oracle.toplink.essentials.queryframework.ObjectLevelModifyQuery.executeInUnitOfWork(ObjectLevelModifyQuery.java:110)
	at oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2233)
	at oracle.toplink.essentials.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:952)
	at oracle.toplink.essentials.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:909)
	at oracle.toplink.essentials.internal.sessions.CommitManager.commitNewObjectsForClassWithChangeSet(CommitManager.java:269)
	at oracle.toplink.essentials.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:190)
	at oracle.toplink.essentials.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet(AbstractSession.java:2657)
	at oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1044)
	at oracle.toplink.essentials.internal.ejb.cmp3.base.RepeatableWriteUnitOfWork.commitToDatabase(RepeatableWriteUnitOfWork.java:403)
	at oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1126)
	at oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl.issueSQLbeforeCompletion(UnitOfWorkImpl.java:2443)
	at oracle.toplink.essentials.internal.ejb.cmp3.base.RepeatableWriteUnitOfWork.issueSQLbeforeCompletion(RepeatableWriteUnitOfWork.java:202)
	at oracle.toplink.essentials.transaction.AbstractSynchronizationListener.beforeCompletion(AbstractSynchronizationListener.java:131)
	at oracle.toplink.essentials.transaction.JTASynchronizationListener.beforeCompletion(JTASynchronizationListener.java:91)
	at com.sun.enterprise.transaction.JavaEETransactionImpl.commit(JavaEETransactionImpl.java:435)
	at com.sun.enterprise.transaction.JavaEETransactionManagerSimplified.commit(JavaEETransactionManagerSimplified.java:852)
	at com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:5114)
	at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:4879)
	at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:2039)
	at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1990)
	at com.sun.ejb.containers.EJBObjectInvocationHandler.invoke(EJBObjectInvocationHandler.java:213)
	at com.sun.ejb.containers.EJBObjectInvocationHandlerDelegate.invoke(EJBObjectInvocationHandlerDelegate.java:79)
	at $Proxy258.cadastrarCliente(Unknown Source)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at com.sun.corba.ee.impl.presentation.rmi.ReflectiveTie.dispatchToMethod(ReflectiveTie.java:144)
	at com.sun.corba.ee.impl.presentation.rmi.ReflectiveTie._invoke(ReflectiveTie.java:174)
	at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatchToServant(CorbaServerRequestDispatcherImpl.java:528)
	at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatch(CorbaServerRequestDispatcherImpl.java:199)
	at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequestRequest(CorbaMessageMediatorImpl.java:1624)
	at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:1486)
	at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleInput(CorbaMessageMediatorImpl.java:990)
	at com.sun.corba.ee.impl.protocol.giopmsgheaders.RequestMessage_1_2.callback(RequestMessage_1_2.java:214)
	at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:742)
	at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.dispatch(CorbaMessageMediatorImpl.java:539)
	at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.doWork(CorbaMessageMediatorImpl.java:2324)
	at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.performWork(ThreadPoolImpl.java:497)
	at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:540)

AVISO: RAR7132: Unable to enlist the resource in transaction. Returned resource to pool. Pool name: [ derby_net_operadorabancario_operadorabancarioPool ]
AVISO: RAR5117 : Failed to obtain/create connection from connection pool [ derby_net_operadorabancario_operadorabancarioPool ]. Reason : com.sun.appserv.connectors.internal.api.PoolingException: java.lang.IllegalStateException: Local transaction already has 1 non-XA Resource: cannot add more resources.  
AVISO: RAR5114 : Error allocating connection : [Error in allocating a connection. Cause: java.lang.IllegalStateException: Local transaction already has 1 non-XA Resource: cannot add more resources.  ]
AVISO: Local Exception Stack: 
Exception [TOPLINK-4002] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: Error in allocating a connection. Cause: java.lang.IllegalStateException: Local transaction already has 1 non-XA Resource: cannot add more resources.  
Error Code: 0

Seu datasource ( um deles pelo menos) é um datasource XA ??? Para esse tipo de transação, envolvendo mais de um banco de dados é preciso que (n-1) datasources sejam XA, para se ter o Two-phase commit (2PC). De uma procurada no google, mesmo pq eu não entendo muito disso, fiz apenas algumas testes nessa situação.

Opa,

nenhum dos 2 é datasource XA, continuo vasculhando no google, já vi vários tópicos sobre esse assunto, mas não achei ainda nehuma forma de configurar isso ou baixar algum driver XA

Consegui pelo método das tentativas;

Deu um pouco de trabalho, até porque não encontrei tutorial algum explicando como resolver.

Há duas formas de resolver:

1ª opção: é só ir no browser e acessar o Glassfish pela url localhost:4848. Chegando lá, ir até a opção JDBC - Grupo de Conexões JDBC. Em nome do grupo, provavelmente deve aparecer várias opções, é só clicar no pool que vc queira que ele passe a fazer transação XA. Daí vai para uma tela Edit JDBC Connection Pool. Como aqui utilizei o banco de dados Derby, no campo Tipo de recurso: está javax.sql.DataSource e em Nome de classe da fonte de dados: está org.apache.derby.jdbc.ClientDataSource. Então é necessário alterar ambos os campos respectivamente para javax.sql.XADataSource e org.apache.derby.jdbc.ClientXADataSource, depois é só clicar no botão salvar.

Se forem duas aplicações distribuídas, só é necessário fazer essa configuração em apenas uma aplicação, mas não há problema algum em alterar essas configurações em ambas. Depois de feita as alterações é só colocar a aplicação pra rodar. Caso continue dando erro, reinicie o Glassfish.

Ou 2ª opção: poderá alterar os arquivos glassfish-resources.xml. Dentro deste arquivo, procurar por datasource-classname=“org.apache.derby.jdbc.ClientDataSource” e alterar para datasource-classname=“org.apache.derby.jdbc.ClientXADataSource” e procurar por res-type=“javax.sql.DataSource” e alterar para res-type=“javax.sql.XADataSource”