Invocar metodo dentro do mesmo EJB

4 respostas
M

Oi a todos!
Sou iniciante no desenvolvimento sobre a plataforma JEE e tenho algumas duvidas, será que alguem podia me ajudar?

Se escrevo um Stateless Session Bean

Exemplo:

package test;

import javax.ejb.Stateless;

/**

  • Session Bean implementation class TestTransaction
    */
    @Stateless
    public class TestTransaction implements TestTransactionLocal {

    @TransactionAttribute(value=SUPPORTS)
    public void metodo1() {

    /* invoke method 2*/
    

    }

    @TransactionAttribute(value=REQUIRES_NEW)
    
    public void metodo2() {
    
    /* do your job */
    
    }
    

}

Minha duvida é:
Se invoco metodo2 desde metodo1 o container abre uma nova transaçao?
Qual seria a maneira correcta de invocar o metodo?
Se invoco dessa forma metodo2(); Nao seria uma chamada normal e assim o container nao iria injetar os serviços? Nao teria que castear para Interface Local e fazer a chamada?
Como se invoca os metodos de un EJB dentro desse EJB tal que o container injete os serviços, arquiteturalmente tem sentido isso?

Desde já agradeço a todos pela ajuda.

4 Respostas

cv1

Nos seus testes, o que deu pra concluir ate agora?

leosouzabh

creio que uma transação não será aberta,
tive problema com isso uma vez, era uma questão de salvar logs no banco, e os logs tinham que ficar isolados na transação, desta forma ficaria como o metodo 2 salvando log e o metod 1 o metodo de “entrada”, não dava certo não, acabei tendo que separar em um outro ejb, injeta-lo e trabalhando fazendo chamadas a ele usando a ref do ejb de log

A

Eh uma boa pergunta essa. Precisava fazer alguns testes para responde-la com mais precisao.

De qualquer forma, o que posso te adiantar eh o seguinte: os metodos chamados em um EJB, um interceptor eh invocado para que uma transacao seja aberta antes mesmo do inicio da execucao do mesmo (claro, se estivermos falando de CMT). Logo no final da execucao desse metodo, se nenhuma RuntimeException for lancada, a transacao eh comitada, senao um rollback eh realizado no final da cadeia de chamada dos EJBs.

Minha opniao seria: uma nova transacao seria aberta. Mas soh testando pra ter certeza.

Abracos

M

Muito obrigado pelo ajuda galera.
Nao tive tempo nenhum de fazer alguns testes depois que postei essa mensagem, entao hoje que tive um tempinho acho que entendi o problema.
Fiz alguns testes com esse codigo, um pouco adaptado.

Interfaces:

package test;

import javax.ejb.Remote;

@Remote
public interface TestTransactionRemote {

public static final String NEW_STATE = "New";
	
public Test metodo1();
public Test metodo2();
public Test metodo3();
//public Test metodo4();
public Test metodo5();
public Test metodo6();

}

package test;

import javax.ejb.Local;

@Local
public interface TestTransactionLocal {

public static final String NEW_STATE = "New";

public Test metodo1();
public Test metodo2();
public Test metodo3();
//public Test metodo4();
public Test metodo5();
public Test metodo6();

}

Implementaçao:

package test;

import javax.annotation.Resource;

// import javax.ejb.EJB;

import javax.ejb.SessionContext;

import javax.ejb.Stateless;

import javax.ejb.TransactionAttribute;

import javax.ejb.TransactionAttributeType;

import javax.persistence.EntityManager;

import javax.persistence.PersistenceContext;

import org.jboss.logging.Logger;

/**

  • Session Bean implementation class TestTransaction
    */
    @Stateless
    public class TestTransaction implements TestTransactionRemote, TestTransactionLocal {

    @Resource
    private SessionContext context;

    @PersistenceContext(unitName=“TestTransaction”)
    EntityManager entityManager;

    Logger log = Logger.getLogger(getClass());

    //@EJB
    //private TestTransactionLocal selfRefr;

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    
    public Test metodo1() {
    
    Test test = metodo6();				
    
    return test;
    
    }
    
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    
    public Test metodo2() {
    
    Test test = metodo6();				
    
    context.setRollbackOnly();
    
    return test;
    
    }
    
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    
    public Test metodo3() {
    
    Test test = ((TestTransactionRemote) this).metodo6(); 		 				
    
    context.setRollbackOnly();
    
    return test;
    
    }
    
    //@TransactionAttribute(TransactionAttributeType.REQUIRED)
    
    //public Test metodo4() {
    
    //Test test = selfRefr.metodo6(); 		 				
    
    <a href="//context.setRollbackOnly">//context.setRollbackOnly</a>();
    
    //return test;
    
    //}
    
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    
    public Test metodo5() {
    
    TestTransactionLocal selfRefr = (TestTransactionLocal) context.lookup(TestTransaction/local);
    
    Test test = selfRefr.metodo6();
    
    context.setRollbackOnly();
    
    return test;
    
    }
    
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    
    public Test metodo6() {
    
    Test test = new Test(TestTransactionRemote.NEW_STATE);
    
    entityManager.persist(test);		
    
    return test;
    
    }
    

}

Resultados:

Metodo 1: Grava a instancia no banco sem problemas.
Olhando o stack trace metodo 1 é chamado por um proxy (EJB Object) que abre a transaçao
(sempre vai abrir uma transaçao pois nao estou abrindo nenhuma no cliente), acontece uma chamada normal e nenhuma transaçao é aberta em metodo6.

Metodo 2: Acontece o mesmo de metodo1, mas como forço um rollback a instancia nao é gravada no banco.

Metodo 3: Tentei castear para interface sem sucesso. Ocorre exatemente o caso de metodo 2.

Metodo 4: Tentei usar DI. O container nao conseguiu fazer o deployment. Basicamente o container tenta injetar a dependencia, como é uma referencia ao proprio
componente e o componente nao esta em estado “Configured” o container aborta.

Metodo 5: Grava a instancia no banco sem problemas. Basicamente fez uma chamada JNDI. Comportamento igual ao metodo 1 só que se abre outro proxy antes da chamada ao metodo6

Conclusao: Nao sei o que a galera opina. A ultima soluçao poderia ser melhorada utilizando um service locator, mas isso penso é um retrocesso ja que DI é uma realidade.
Nao sei se tem muito sentido chamadas(dentro de um mesmo EJB) com serviços fornecidos pelo container. Falo de uma maneira arquitetural. Como nao tenho experiencia com EJBS, nao sei se na vida real existem arquiteturas que funcionem assim.

Bom de qualquer modo, agradeço a galera pela ajuda.

Criado 25 de abril de 2010
Ultima resposta 15 de mai. de 2010
Respostas 4
Participantes 4