Desenvolvimento - Java
EJB3 + DAO
Muito se discute na comunidade se devemos usar um mecanismo de persistência com EJB3, pois o container EJB somente irá injetar o EntityManger nas classes (Servlets e EJB) que são gerenciadas pelo container web, ou seja, isso é um problema pois o nosso DAO não é gerenciado pelo container web, e ele com certeza precisa do EntityManager.
por Ronildo Braga JuniorMuito se discute na comunidade se devemos usar um mecanismo de persistência com EJB3, pois o container EJB somente irá injetar o EntityManger nas classes(Servlets e EJB) que são gerenciadas pelo container web, ou seja, isso é um problema pois o nosso DAO não é gerenciado pelo container web, e ele com certeza precisa do EntityManager.
Esse problema não existia anteriormente porque o nosso DAO era responsável por criar a conexão com o banco de dados, o que nos trazia mais problemas, pois tínhamos a questão da transação, que não podia ser gerenciada pelo DAO, apesar deste criar a conexão com o banco de dados.
Outro ponto negativo do EJB3 + DAO é que o nosso DAO não é algo mais complexo, portanto fica simples você inserir um registro no banco de dados com poucas linhas:
Mas nem tudo é flores, essa abordagem não serve para nós, pois não estamos fazendo um sistema para a padaria da sua esquina, ou para lojinha do seu tio.
O nosso sistema não pode simplismente gravar a entidade no banco de dados e esperar que tudo ocorra normalmente, o método acima pode precisar de uma transação para duas entidades diferentes, ou pior, pode lançar uma exceção do banco de dados para o cliente. Imagina o seu EJB tratando as exceções do banco de dados mais as de negócio do EJB, não vai ficar muito elegante né :-/
Portanto aconselho sim, que você use um mecanismo de persistência com o seu EJB, e vou demonstrar abaixo como você pode fazer isso.
Primeiro vamos criar a nossa fábrica de DAO que será responsável por injetar o nosso EntityManager em nossos DAOs. Esta fábrica é um EJB local pois não queremos que clientes fora do nosso container web façam uso dessa classe.
Segue abaixo a interface da nossa fábrica.
@Stateless significa que não vamos manter um estado de conversação para um cliente particular. Quando um cliente invoca o método de um bean stateless, as variáveis do bean podem conter um estado, mas somente para a duração da chamada. Ao terminar a execução, o estado é encerrado. Exceto durante a chamada do método, todas as instâncias de um bean stateless são equivalentes, permitindo que o container EJB atribua uma instância a qualquer cliente
@PersistenceContext significa que esta variável deve ser injetada com o EntityManager através do container web.
O PersistenceContext é um conjunto de objetos/entidades gerenciadas por um EntityManager. Objetos que representam entidades serão recuperados, inseridos ou removidos de um banco de dados pelo EntityManager. Estas entidades estarão anexadas ao contexto de persistência o qual será fechado/removido quando o EntityManager for fechado. Se o contexto for mantido ativo porém o objeto/entidade for desanexada do contexto, então esta entidade não mais será gerenciado pelo EntityManager e modificações na sua instância não serão refletidos no banco de dados
@TransactionAttribute (TransactionAttributeType.NEVER)
Isto significa que o nosso método não irá iniciar uma transação para instanciar as classes, pois não faz sentido já que estamos apenas retornando um objeto sem fazer qualquer alteração no banco de dados.
Agora que você já sabe como injetar EntityManager em nossos DAOs, vamos fazer uso deles em nossos EJB, segue abaixo um exemplo:
@EJB isso irá fazer como que a nossa variável receba a nossa fábrica de DAOs
@PostConstruct aqui criamos uma instância para o nosso repositório, não podemos colocar isso no construtor da classe pois precisamos esperar a injeção da nossa fábrica.
@TransactionAttribute(TransactionAttributeType.REQUIRED) Agora sim vamos usar uma transação, simples assim, nada de XML, apenas anotamos para que o container web saiba que aqui ele precisa iniciar uma transação.
Pronto, acabamos aqui, você deve se perguntar: Cade a tal da validação, tratamento de exceção, lógica de negocio e etc? Pois bem... deixamos isso para o próximo artigo pois vamos descrever como você deve usar os seus EJB, e como configurar a sua aplicação.
Esse problema não existia anteriormente porque o nosso DAO era responsável por criar a conexão com o banco de dados, o que nos trazia mais problemas, pois tínhamos a questão da transação, que não podia ser gerenciada pelo DAO, apesar deste criar a conexão com o banco de dados.
Outro ponto negativo do EJB3 + DAO é que o nosso DAO não é algo mais complexo, portanto fica simples você inserir um registro no banco de dados com poucas linhas:
@PersistenceContext private EntityManager em; public void persist(Object o){ em.persist(o); }Pois é, isso mesmo, o código acima irá gravar qualquer entidade no banco de dados, você pode colocar essa função no seu EJB e "eureka" resolvido o nosso mecanismo de persistência.
Mas nem tudo é flores, essa abordagem não serve para nós, pois não estamos fazendo um sistema para a padaria da sua esquina, ou para lojinha do seu tio.
O nosso sistema não pode simplismente gravar a entidade no banco de dados e esperar que tudo ocorra normalmente, o método acima pode precisar de uma transação para duas entidades diferentes, ou pior, pode lançar uma exceção do banco de dados para o cliente. Imagina o seu EJB tratando as exceções do banco de dados mais as de negócio do EJB, não vai ficar muito elegante né :-/
Portanto aconselho sim, que você use um mecanismo de persistência com o seu EJB, e vou demonstrar abaixo como você pode fazer isso.
Primeiro vamos criar a nossa fábrica de DAO que será responsável por injetar o nosso EntityManager em nossos DAOs. Esta fábrica é um EJB local pois não queremos que clientes fora do nosso container web façam uso dessa classe.
Segue abaixo a interface da nossa fábrica.
@Local public interface RepositorySession { @TransactionAttribute(TransactionAttributeType.NEVER) public LoginRepository getLoginRepository(); @TransactionAttribute(TransactionAttributeType.NEVER) public TimesheetRepository getTimesheetRepository(); }Agora segue abaixo a nossa implementação da fábrica.
@Stateless public class RepositorySessionImpl implements RepositorySession{ @PersistenceContext private EntityManager em; @TransactionAttribute(TransactionAttributeType.NEVER) public LoginRepository getLoginRepository(){ return new LoginDAO().setEntityManager(em); } @TransactionAttribute(TransactionAttributeType.NEVER) public TimesheetRepository getTimesheetRepository(){ return new TimesheetDAO().setEntityManager(em); } }você precisa reparar em três anotações importantes:
@Stateless significa que não vamos manter um estado de conversação para um cliente particular. Quando um cliente invoca o método de um bean stateless, as variáveis do bean podem conter um estado, mas somente para a duração da chamada. Ao terminar a execução, o estado é encerrado. Exceto durante a chamada do método, todas as instâncias de um bean stateless são equivalentes, permitindo que o container EJB atribua uma instância a qualquer cliente
@PersistenceContext significa que esta variável deve ser injetada com o EntityManager através do container web.
O PersistenceContext é um conjunto de objetos/entidades gerenciadas por um EntityManager. Objetos que representam entidades serão recuperados, inseridos ou removidos de um banco de dados pelo EntityManager. Estas entidades estarão anexadas ao contexto de persistência o qual será fechado/removido quando o EntityManager for fechado. Se o contexto for mantido ativo porém o objeto/entidade for desanexada do contexto, então esta entidade não mais será gerenciado pelo EntityManager e modificações na sua instância não serão refletidos no banco de dados
@TransactionAttribute (TransactionAttributeType.NEVER)
Isto significa que o nosso método não irá iniciar uma transação para instanciar as classes, pois não faz sentido já que estamos apenas retornando um objeto sem fazer qualquer alteração no banco de dados.
Agora que você já sabe como injetar EntityManager em nossos DAOs, vamos fazer uso deles em nossos EJB, segue abaixo um exemplo:
@Local public interface TimesheetFacade { @PostConstruct public void initialize(); @TransactionAttribute(TransactionAttributeType.REQUIRED) public void persist(Timesheet Timesheet); }Veja que eu anotei a minha interface como @Local, mas você poderia anotar com @Remote pois esta classe pode ser usada por clientes externos, pois esta classe contem toda a nossa lógica de negocio, validações e controle das exceções e não tem problema em disponibilizar ela fora do nosso container. Agora segue abaixo a nossa implementação:
@Stateless public class TimesheetFacadeImpl implements TimesheetFacade { @EJB RepositorySession repository; TimesheetRepository timesheetRepository; @PostConstruct public void initialize() { timesheetRepository = repository.getTimesheetRepository(); } @TransactionAttribute(TransactionAttributeType.REQUIRED) public void persist(Timesheet timesheet) { timesheetRepository.persist(timesheet); } }Precisamos prestar atenção para 3 anotações:
@EJB isso irá fazer como que a nossa variável receba a nossa fábrica de DAOs
@PostConstruct aqui criamos uma instância para o nosso repositório, não podemos colocar isso no construtor da classe pois precisamos esperar a injeção da nossa fábrica.
@TransactionAttribute(TransactionAttributeType.REQUIRED) Agora sim vamos usar uma transação, simples assim, nada de XML, apenas anotamos para que o container web saiba que aqui ele precisa iniciar uma transação.
Pronto, acabamos aqui, você deve se perguntar: Cade a tal da validação, tratamento de exceção, lógica de negocio e etc? Pois bem... deixamos isso para o próximo artigo pois vamos descrever como você deve usar os seus EJB, e como configurar a sua aplicação.