Entity Beans (EJB 3) no JBOSS

40 respostas
M

Olá pessoal,

Estou tentando fazer uma aplicação que use entity beans especificação do EJB 3 pra rodar no JBOSS. Mas estou encontrando dificuldades, tanto para fazê-la funcionar quanto para encontrar informações a respeito. Já garimpei na internet mas não encontro nada direto sobre o assunto, e quando encontro é cheio de links quebrados ou/e classes faltando.

Alguêm conhece algum bom tutorial, onde eu possa estudar e botar pra funcionar entity beans no JBOSS?

Abraços,
Machado

40 Respostas

F

http://docs.jboss.org/ejb3/app-server/tutorial/

M

Opa! Valeu pela dica. Algumas coisas ficaram mais claras agora, mas outras ainda continuam meio obscuras pra mim.

Eu posso ou não posso usar injeção de entity beans no JBOSS?

O código abaixo, deveria funcionar ou eu tenho que fazer um ContextLookup?

package example;

import java.io.IOException;
import java.io.PrintWriter;

import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class LoginServlet extends HttpServlet {

	// this injects the default entity manager factory
	@PersistenceContext (name = "em1")
	EntityManager em;

	public void service(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {

		// Create an EM here so that only this thread uses it.
		try {
			System.out.println("\n\n" + em);
			resp.setContentType("text/html");
			PrintWriter out = resp.getWriter();
			out.println("<HTML> <HEAD> <TITLE> Login Successful "
					+ "</TITLE> </HEAD> <BODY BGCOLOR=white>");

			String name = req.getParameter("name");
			String password = req.getParameter("password");

			// Do a db look up in UserCredential table with the name as the PK
			UserCredential credential = em.find(UserCredential.class, name);

			System.out.println("\n\n" + credential.getName());
			// em.find returns null if not found, hence null check.
			if (credential != null && credential.isMatchingPassword(password)) {
				out.println("Welcome " + name);
			} else {
				out.println("Incorrect user name or password.");
			}

			out.println("</BODY> </HTML> ");
		} finally {
			// we must close em so that provider can release resources.
			em.close();
		}
	}

	public void init(ServletConfig config) throws ServletException {
		super.init(config);
	}

}

Quando eu rodo ela recebo um NullPointerException no finally. Testando esse EntityManager realmente está null, mas não faço nem idéia do porque. Talvez porque algum arquivo de configuração esteja errado ou simplismente o JBOSS não suporta alguma coisa que estou tentando fazer.

Segue meu persistence.xml:

<persistence version="1.0">
	<persistence-unit name="em1">
		<jta-data-source>java:/EntitySQL</jta-data-source>
		<properties>
			<property name="jboss.entity.manager.jndi.name"
				value="java:/Manager1" />
			<property name="jboss.entity.manager.factory.jndi.name"
				value="java:/Manager1Factory" />
		</properties>
	</persistence-unit>
</persistence>

E o meu *-ds:

<?xml version="1.0" encoding="UTF-8"?>

<!-- $Id: mysql-ds.xml,v 1.3.2.3 2006/02/07 14:23:00 acoliver Exp $ -->
<!--  Datasource config for MySQL using 3.0.9 available from:
http://www.mysql.com/downloads/api-jdbc-stable.html
-->

<datasources>
  <local-tx-datasource>
    <jndi-name>EntitySQL</jndi-name>
    <connection-url>jdbc:mysql://localhost/webapps_teste</connection-url>
    <driver-class>com.mysql.jdbc.Driver</driver-class>
    <user-name>root</user-name>
    <password>projetofinal</password>
    <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
    <!-- should only be used on drivers after 3.22.1 with "ping" support
    <valid-connection-checker-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLValidConnectionChecker</valid-connection-checker-class-name>
    -->
    <!-- sql to call when connection is created
    <new-connection-sql>some arbitrary sql</new-connection-sql>
      -->
    <!-- sql to call on an existing pooled connection when it is obtained from pool - MySQLValidConnectionChecker is preferred for newer drivers
    <check-valid-connection-sql>some arbitrary sql</check-valid-connection-sql>
      -->

    <!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml (optional) -->
    <metadata>
       <type-mapping>mySQL</type-mapping>
    </metadata>
  </local-tx-datasource>
</datasources>

Pelo menos checando no console JMX do JBOSS aparentemente esse JNDI esta correto.

Quem puder/tiver paciência de me dar uma força fico devendo uma.

Abçs,
Machado

P

Pela especificacao, deveria funcionar!

mas voce vai ter um problema de ter uma variavel de instancia em uma Servlet como um EntityManager por causa do acesso concorrente. prefira inserir um EntityManagerFactory ou entao anotar com PersisnteceContext a classe, para puxar o EntityManager por jndi

M

Acho que já está anotado com o PersistenceContext, mas eu li em algum lugar que é melhor usar um EntityManagerFactory mesmo.
O detalhe é que coloquei o Factory e continuo recebendo um NullPointerException. :cry:

Bom, vou dar uma revisada total no cótigo, e então partir pro desespero e baixar o JBoss 4.05, talvez seja alguma coisa relacionada a minha instalação do JBoss (4.04).

E valeu pela ajuda, agora sei que não estou fazendo nada absurdo, deve ser alguma bobeira.

M

Pessoal,

Quero deixar uma solução que encontrei caso alguém tenha o mesmo problema, e uma pergunta.

Primeiro a sulução. Tirei os annotations.

O código da classe onde estava acontecendo a exceção ficou assim:

package example;

import java.io.IOException;
import java.io.PrintWriter;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.PersistenceContext;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Stateless
public class LoginServlet extends HttpServlet {

    // this injects the default entity manager factory
	EntityManagerFactory emf = Persistence.createEntityManagerFactory("em1");
	
	
	
    public void service ( HttpServletRequest req , HttpServletResponse resp) 
        throws ServletException, IOException {

    	EntityManager em = emf.createEntityManager();
        
        try {
            resp.setContentType("text/html");
            PrintWriter out = resp.getWriter();
            out.println("<HTML> <HEAD> <TITLE> Login Successful " +
                        "</TITLE> </HEAD> <BODY BGCOLOR=white>");

            String name = req.getParameter("name");
            String password = req.getParameter("password");
        
            // Do a db look up in UserCredential table with the name as the PK
            UserCredential credential = em.find(UserCredential.class, name);
    
            // em.find returns null if not found, hence null check.
            if (credential != null && credential.isMatchingPassword(password)) {
                out.println("Welcome " + name);
            } else {
                out.println("Incorrect user name or password.");
            }
    
            out.println("</BODY> </HTML> ");
        } finally {
            // we must close em so that provider can release resources.
            em.close();
        }
    }

    public void  init( ServletConfig config) throws ServletException {
        super.init(config);
    }
    
}

Acho que ficou melhor do que antes por causa da inclusão do Factory…

A pergunta é… Alguém sabe se JBOSS aceita ou não annotations??

Falou.
Machado

H

O JBoss aceita annotations, o problema é o container servlet (Tomcat) que não suporta injeção de dependência na atual versão (5.x), que ja vem encorporado ao JBoss.

Há rumores de que na próxima versão (6) é que o tomcat vai suportar annotations. Por enquanto a solução que vc encontrou é a única possível…

Sobre a versão do JBoss, existe um projeto no JBoss, JEMS Installer, que é um pacotão contendo a versão mais atual dom JBoss e do EJB3, mais uns bagulhos. A vantagem é que não precisa ficar ‘remendando’ a instalação do JBoss instalando separado o EJB3 e configurando. segue o link caso açguém queira dá uma olhada: http://labs.jboss.com/portal/jemsinstaller/?prjlist=false

Obs: Na instalação do JBoss tem que escolhar a opção ‘EJB-3’ pra funcionar. Se escolher ‘All’ ele não instala o EJB3…

[]'s

M

Hummm…

O que confunde é que ele usa como container de servlet o Tomcat e um módulo de EJB3.
Aí no caso ele aceita annotation pra se fazer as classes de persistência, como @entity, mas não aceita no servlet na hora de fazer a injeção.

Então o lance é ficar ligado quando sair a próxima versão…

Flw

C

Estou com um problema parecido, só que nos meus DAOs. Retirei o @PersistenceContext e o context do sesseion bean e passei para o DAO, que fica em outro pacote ( Tenho de manter os DAOs e os POJOs separados do Session Bean, em um pacote a parte, pois também pretendo usá-los em uma aplicação Stand-Alone )

e o código que antes funcionava deixou de funcionar pq o EntityManager fica null

public class EJB3DAO <E> implements IGenericDAO <E> {
    
    @PersistenceContext()
    private EntityManager em;
    
    /** Creates a new instance of EJB3DAO */
    public EJB3DAO() {
    }

    public void create(E e) {
        em.getTransaction().begin();
        em.persist(e);
        em.getTransaction().commit();
        
    }
    ...
    ...
    ...
}
C

Descobri a causa do problema mas não me agradou muito:

“injection only occurs in EJBs, not in plain classes”

http://www.jboss.org/?module=bb&op=viewtopic&t=67611

C

Ow Carlos, lá no seu @PersistenceContext tenta deixar implicito o unitname.

@PersistenceContext(unitName="<nomeDaSuaUnidadeDePersitencia>")
D

Paulo Silveira:
Pela especificacao, deveria funcionar!

mas voce vai ter um problema de ter uma variavel de instancia em uma Servlet como um EntityManager por causa do acesso concorrente. prefira inserir um EntityManagerFactory ou entao anotar com PersisnteceContext a classe, para puxar o EntityManager por jndi

O mesmo se aplica para EJBs que referenciam outros EJBs?

T

O problema que o Paulo falou se refere ao entityManager não ser threadSafe por natureza… Porém algumas implementações como a da Oracle por exemplo garantem a qualidade ThreadSafe do entityManager, porém vc cai na dependência de toolvendors…

T

danieldestro:
Paulo Silveira:
Pela especificacao, deveria funcionar!

mas voce vai ter um problema de ter uma variavel de instancia em uma Servlet como um EntityManager por causa do acesso concorrente. prefira inserir um EntityManagerFactory ou entao anotar com PersisnteceContext a classe, para puxar o EntityManager por jndi

O mesmo se aplica para EJBs que referenciam outros EJBs?

Se vc está falando de classes como Servelets e MBeans, sim. Não é legal injetar Stateful SessionBeans em classes como servlets e MBeans devido à concorrência, embora o mesmo não se aplica a Stateless SessionBeans. No caso de @EJB em outro EJB não há problemas, daí o caso dos EAOs poderem ser injetados nos session Beans se os mesmo forem EJBs.

T

carlos.macleod:
Descobri a causa do problema mas não me agradou muito:

“injection only occurs in EJBs, not in plain classes”

http://www.jboss.org/?module=bb&op=viewtopic&t=67611

Por isso que ainda se usa EJB3 com Spring2.x…

C

E é possível utilizá-lo em uma aplicação stand alone ( Sem container EJB ou Servlet / JSP ) ?

T

EntityBeans e JPA sim. SessionBeans não. Muito menos injetar o EntityManager nos EAOS.

C

cetr1n:
Ow Carlos, lá no seu @PersistenceContext tenta deixar implicito o unitname.

@PersistenceContext(unitName="<nomeDaSuaUnidadeDePersitencia>")

Dá NPE do mesmo jeito ( O JBoss nao injeta o EntityManager dentro do DAO )

C

Falo do Spring, não de Session Beans.

T

Falo do Spring, não de Session Beans.

desculpe… SIM.rs

T

carlos.macleod:
cetr1n:
Ow Carlos, lá no seu @PersistenceContext tenta deixar implicito o unitname.

@PersistenceContext(unitName="<nomeDaSuaUnidadeDePersitencia>")

Dá NPE do mesmo jeito ( O JBoss nao injeta o EntityManager dentro do DAO )

Seu DAO é um EJB?

C

Tecnoage:

Seu DAO é um EJB?

Não. O EJB acessa o DAO. Preciso deixar o DAO fora do EJB, para que seja possível uma aplicação stand alone compartilhar do mesmo código.

T

Na teoria vc teria que fazer seus DAOS como EAOS e transformá-los em EJBs. Se vc não pode fazer isso, faça um service locator e pegue o DAO via JNDI mesmo.

C

Complicou. Qual a necessidade de bindar JNDI para o DAO ? Ele não pode estar em um jar a parte, utilizado pelo EJB ? ( A outra aplicação que é stand alone, nao pegará os DAOs do AS, pois será construida para rodar sem o mesmo )

Ume breve explicação do motivo:
Minha aplicação é de varejo, e nem todos os meus clientes ( alias, a minoria deles ) terão uma estrutura física que permita um aplication server. A maioria das lojas de shopping possui apenas uma máquina, e nao tem sentido instalar um AS para rodar a aplicação. Por outro lado, não posso ignorar os clientes que precisarão de integração entre lojas, loja virtual, load balancing, centralização dos dados, etc…

Minha estrutura é a seguinte:

Extasy-Enterprise-EJB.jar --> Contem as interfaces e implementações dos Facades ( Meus Session Beans ), configurações do AS e a Persistence unit.

Extasy-Core.jar —> Contém as entiaddes anotadas e os DAOs ( Comum tanto a aplicação Enterprise quanto a Stand Alone )

Para a aplicação Stand-alone funcionar, o EntityManager deve estar nos DAOs. Os Session Beans seguem o formato de CrUDe, mas que simplesmente fazem chamadas aos metodos CrUDe do DAO.

Quando fazia da forma convencional ( com o EM dentro do Session Bean ), o EM era injetado corretamente. Resolvi então fazer a mudança para a estrutura que citei acima. Aí começaram meus problemas:

1- A injeção nao funcionava no DAO
Solução: Utilizar EntityManagerFactory

2- Na geração inicial dos dados, feita logo que o módulo ejb era instalado, dava tudo certo ( pois o deployer sabia como obter o entity manager a partir do Persistence unit ), mas quando eu tentava criar o EntityManagerFactory a partir do PU não mão ( já que este não era injetado ) para utilizá-lo com o DAO, tinha diversos problemas com o JTA… (Ex: “The chosen transaction strategy requires access to the JTA TransactionManager”)
Solução: Bindar o EM e o EM Factory via JNDI pelo PU

3- Agora funciona. Só não sei o que está fazendo a diferença entre criar o EntityManagerFactory passando como parâmetro a PU e bindá-lo na PU, pegando por JNDI. Parece quando que o EMF é criado passando como parâmetro a PU, o container “esquece” de setar algumas propriedades ou de bindar alguma coisa. O problema agora é que não fica compatível com Stand Alone, principalmente pelo fato de ter aquelas referencias aos JNDI do JBOSS ( De repente até fique compatível, pois a aplicação stand alone com Hibernate Entity Manager utiliza tanta coisa do JBoss, que dá a impressão de que roda dentro de um microkernel do mesmo, só que embarcado - Até os logs são iguais ).

Agora que expliquei tudo, lá vão as perguntas:

Tem alguma outra alternativa sem ser bindar o EMF e o EM por JNDI ?

Em ultimo caso: O Spring resolveria meu problema ( tanto no AS quanto Stand alone ), sem ser mais um monte de jars, com um monte de configurações para dificultar ainda mais a programação ?

Aqui vão alguns dos fontes:

Persistence Unit

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
  <persistence-unit name="Extasy-Enterprise-ejbPU" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>java:/MySqlDS</jta-data-source>
    <class>com.highlands.model.inventario.Modelo</class>
    <exclude-unlisted-classes>true</exclude-unlisted-classes>
    <properties>
      <property name="jboss.entity.manager.jndi.name" value="java:/Manager1"/>
      <property name="jboss.entity.manager.factory.jndi.name" value="java:/Manager1Factory"/>
      <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
    </properties>
  </persistence-unit>
</persistence>

Classe anotada

/*
 * Modelo.java
 *
 * Created on 27 de Agosto de 2007, 21:30
 */

package com.highlands.model.inventario;

import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/**
 * Classe de entidade Modelo
 * 
 * @author macleod
 */
@Entity
public class Modelo implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    
    @Column(length=60, unique=true, nullable=false)
    private String descricao;
    
    /** Creates a new instance of Modelo */
    public Modelo() {
    }

    /**
     * Define o id deste Modelo.
     * @return o id
     */
    public Integer getId() {
        return this.id;
    }

    /**
     * Define o id deste Modelo para o valor especificado.
     * @param id o novo id
     */
    protected void setId(Integer id) {
        this.id = id;
    }
    
    public String getDescricao() {
        return descricao;
    }

    public void setDescricao(String descricao) {
        this.descricao = descricao;
    }


    /**
     * Retorna um valor de c&#65533;digo hash para o objeto.  Esta implementa&#65533;&#65533;o computa
     * um valor de c&#65533;digo hash baseado nos campos id deste objeto.
     * @return um valor de c&#65533;digo hash para este objeto.
     */
    @Override
    public int hashCode() {
        int hash = 0;
        hash += (this.id != null ? this.id.hashCode() : 0);
        return hash;
    }

    /**
     * Determina se outro objeto &#65533; igual a este Modelo.  O resultado &#65533;
     * <code>true</code> se e somente se o argumento n&#65533;o for nulo e for um objeto Modelo o qual
     * tem o mesmo valor para o campo id como este objeto.
     * @param object o objeto de refer&#65533;ncia com o qual comparar
     * @return <code>true</code> se este objeto é o mesmo como o argumento;
     * <code>false</code> caso contr&#65533;rio.
     */
    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Modelo)) {
            return false;
        }
        Modelo other = (Modelo)object;
        if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) return false;
        return true;
    }

    /**
     * Retorna uma representação literal deste objeto.  Esta implementação cria
     * uma representação baseada nos campos id.
     * @return uma representação literal deste objeto.
     */
    @Override
    public String toString() {
        return "com.highlands.model.inventario.Modelo[id=" + id + "]";
    }

    
}

Session Bean Stateless

/*
 * ModeloFacade.java
 *
 * Created on 27 de Agosto de 2007, 21:31
 * 
 */

package com.highlands.model.inventario;

import com.highlands.persistence.DAOFactory;
import com.highlands.persistence.IGenericDAO;
import java.util.List;
import javax.ejb.Stateless;

/**
 *
 * @author macleod
 */
@Stateless
public class ModeloFacade implements ModeloFacadeLocal, ModeloFacadeRemote {

    
    /** Creates a new instance of ModeloFacade */
    public ModeloFacade() {
    }

    @SuppressWarnings("unchecked")
    public void create(Modelo modelo) {
        IGenericDAO dao = DAOFactory.getDAO();
        dao.create(modelo);        
    }

    public void edit(Modelo modelo) {
        @SuppressWarnings("unchecked")
	IGenericDAO<Modelo> dao = DAOFactory.getDAO();
        dao.edit(modelo);

    }

    public void destroy(Modelo modelo) {
        @SuppressWarnings("unchecked")
	IGenericDAO<Modelo> dao = DAOFactory.getDAO();
        dao.destroy(modelo);
    }

    public Modelo find(Object pk) {
        @SuppressWarnings("unchecked")
	IGenericDAO<Modelo> dao = DAOFactory.getDAO();
        return dao.find(Modelo.class, pk);
    }

    public List findAll() {
        @SuppressWarnings("unchecked")
	IGenericDAO<Modelo> dao = DAOFactory.getDAO();
        return dao.findAll();
    }
    
}

Remote

/*
 * ModeloFacadeRemote.java
 *
 * Created on 27 de Agosto de 2007, 21:31
 *
 */

package com.highlands.model.inventario;

import java.util.List;
import javax.ejb.Remote;

/**
 *
 * @author macleod
 */
@Remote
public interface ModeloFacadeRemote {
    void create(Modelo modelo);

    void edit(Modelo modelo);

    void destroy(Modelo modelo);

    Modelo find(Object pk);

    List findAll();
    
}

Interface DAO

/*
 * IGenericDAO.java
 *
 * Created on 28 de Agosto de 2007, 03:37
 * 
 */

package com.highlands.persistence;

import java.util.List;

/**
 *
 * @author macleod
 */
public interface IGenericDAO <E> {
    
    public void create(E e);

    public void edit(E e);

    public void destroy(E e);
    
    public E find(Class<E> c, Object pk);

    public List <E> findAll();
    
}

Implementação de DAO para trabalhar com JPA / Entity manager

/*
 * EJB3DAO.java
 *
 * Created on 28 de Agosto de 2007, 03:55
 *
 */

package com.highlands.persistence;

import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

/**
 *
 * @author macleod
 */

public class EJB3DAO <E> implements IGenericDAO <E> {
    
    
    private EntityManager em;

    /** Creates a new instance of EJB3DAO */
    public EJB3DAO() {
	em = buscaEntityManager();
    }

    public void create(E e) {	
        em.persist(e);
    }

    public void edit(E e) {
        em.merge(e);
    }

    public void destroy(E e) {
        em.merge(e);
        em.remove(e);
    }

    public E find(Class<E> c, Object pk) {
        return em.find(c, pk);
    }

    public List<E> findAll() {
        return null;
    }

    private EntityManager buscaEntityManager(){
	EntityManager result = null;
        try {
            javax.naming.InitialContext ic = new javax.naming.InitialContext();
	    EntityManagerFactory emf = (EntityManagerFactory)ic.lookup("java:/Manager1Factory");
            result = emf.createEntityManager();
	    
        } catch (Exception ex) {
            Logger.getLogger("global").log(Level.SEVERE, null, ex);
        }
	return result;
    }
    
}

DAO Factory

/*
 * DAOFactory.java
 *
 * Created on 28 de Agosto de 2007, 03:53
 *
 */

package com.highlands.persistence;

/**
 *
 * @author macleod
 */
public class DAOFactory {
    
    private static IGenericDAO instance = null;    
    
    private DAOFactory(){
    }
    
    public static IGenericDAO getDAO(){
        if (instance == null){
            instance = new EJB3DAO<Object>();
        }
        return instance;
    }
}

Aplicação cliente de Teste

/*
 * Main.java
 * 
 * Created on 30/08/2007, 01:06:23
 * 
 */

package extasyenterprise;

import com.highlands.model.inventario.Modelo;
import com.highlands.model.inventario.ModeloFacadeRemote;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.NamingException;

/**
 *
 * @author macleod
 */
public class Main {

    /** Creates a new instance of Main */
    public Main() {
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        ModeloFacadeRemote f = null;
        try {
            javax.naming.InitialContext ic = new javax.naming.InitialContext();
            f = (ModeloFacadeRemote)(ic.lookup("Extasy-Enterprise/ModeloFacade/remote"));
                        
        } catch (NamingException ex) {
            Logger.getLogger("global").log(Level.INFO, null, ex);
        }
       
        Modelo m = new Modelo();
            
        m.setDescricao("Glórias a Deus !!! " + new Date());
            
        f.create(m);
        

    }

}

Abraços e obrigado pela atenção,

Carlos MacLeod

D

Acho que você terá que gerar dois JARs um pouco diferentes. Um com um persistence.xml para o Container e outro persistence.xml para o modo Stand-alone. E evitar de usar JNDI.

T

agora que vc expôs todo o prolema (hehehe) preciso de um tempinho para analisar… à tarde eu passo por aki…

C

Na verdade o meu problema é exatamente esse. Como me livrar do JNDI no container ? Como havia dito, o PU funciona corretamente no container para o deploy, mas não consigo pegar o EntityManagerFactory a partir do PU, dentro do DAO ( já que o container não faz a injeção para mim )

Mesmo com PUs diferentes para cada Stand-alone e enterprise, não resolve se antes nao me livrar desse maldito JNDI poluindo meu DAO.

Seria uma boa prática passar o EntityManager como parâmetro na criação do DAO ? Acho que isso resolveria meu problema.

T

isso ainda não sei te responder, mas nessa questão de injeção de Dependência, tome cuidado com a escalabilidade no seu sistema. Em alguns contextos, o negócio funciona em tempo de deploy e teste, mas quando entra em produção vc pode ter muitas dores de cabeça…

T

isso ainda não sei te responder, mas nessa questão de injeção de Dependência, tome cuidado com a escalabilidade no seu sistema. Em alguns contextos, o negócio funciona em tempo de deploy e teste, mas quando entra em produção vc pode ter muitas dores de cabeça…

D

Isso não resolve?

EntityManagerFactory emf = Persistence.createEntityManagerFactory("em1"); // ... EntityManager em = emf.createEntityManager();

B
carlos.macleod:
Estou com um problema parecido, só que nos meus DAOs. Retirei o @PersistenceContext e o context do sesseion bean e passei para o DAO, que fica em outro pacote ( Tenho de manter os DAOs e os POJOs separados do Session Bean, em um pacote a parte, pois também pretendo usá-los em uma aplicação Stand-Alone )

e o código que antes funcionava deixou de funcionar pq o EntityManager fica null

public class EJB3DAO <E> implements IGenericDAO <E> {
    
    @PersistenceContext()
    private EntityManager em;
    
    /** Creates a new instance of EJB3DAO */
    public EJB3DAO() {
    }

    public void create(E e) {
        em.getTransaction().begin();
        em.persist(e);
        em.getTransaction().commit();
        
    }
    ...
    ...
    ...
}

Cara se vc nao usar @Stateful ou @Stateless em sua classe, o JBoss não vai Injetar o PersistenceContext e vai ficar dando erro de null pointer exception.

B

Na verdade o meu problema é exatamente esse. Como me livrar do JNDI no container ? Como havia dito, o PU funciona corretamente no container para o deploy, mas não consigo pegar o EntityManagerFactory a partir do PU, dentro do DAO ( já que o container não faz a injeção para mim )

Mesmo com PUs diferentes para cada Stand-alone e enterprise, não resolve se antes nao me livrar desse maldito JNDI poluindo meu DAO.

Seria uma boa prática passar o EntityManager como parâmetro na criação do DAO ? Acho que isso resolveria meu problema.

Cara, da uma olhada no JBoss Seam, talvez te ajude.

T

Talvez ajude sim… O problema é que utilizar o EMF é deixar de lado algumas das melhores ideias do EJB3. Seria um absurdo no seu caso ter duas implementações do DAO? mesmo que uma extendesse da outra?

M

Bem… como o IoC do EJB3 só funciona para objetos gerenciados pelo conteiner, eu costumo trabalhar da seguinte forma.

sessionBean --> DaoFactory --> DAO

@Stateless
public class SessionBeanXXX {
    
     @EJB
     private DaoFactory daoFactory;

     public void salvarProduto(Produto prod){
            ProdutoDAO dao = daoFactory.getProdutoDAO();
            dao.persist(prod);
     }

}



@Stateless
public class DaoFactory {
    
    @PersistenceContext(unitName = "oracle")  
     private EntityManager entityManager;

     public ProdutoDAO getProdutoDAO(){
            IDAO dao = new ProdutoDAOImpl();
            dao.setEntityManager(entityManager);
            return dao;
     }

}

public interface IDAO{
     public void setEntityManager(EntityManager manager);
}

public interface IProdutoDAO extends IDAO{
   //alguns metodos
}

public class ProdutoDAOImpl implements IProdutoDAO{
   // implenta o setEntityManager
}

Todo DAO deve implementar a interface IDAO, para garantir que ele terá o método setEntityManager().

O DaoFactory está implementado de uma forma muito simples. Faça-o como você quiser.

É lógico que este código não é o melhor. É apenas para demostrar uma possível arquitetura para resolver este problema.

M

marcelo_mococa:
Bem… como o IoC do EJB3 só funciona para objetos gerenciados pelo conteiner, eu costumo trabalhar da seguinte forma.

sessionBean --> DaoFactory --> DAO

@Stateless
public class SessionBeanXXX {
    
     @EJB
     private DaoFactory daoFactory;

     public void salvarProduto(Produto prod){
            ProdutoDAO dao = daoFactory.getProdutoDAO();
            dao.persist(prod);
     }

}



@Stateless
public class DaoFactory {
    
    @PersistenceContext(unitName = "oracle")  
     private EntityManager entityManager;

     public ProdutoDAO getProdutoDAO(){
            IDAO dao = new ProdutoDAOImpl();
            dao.setEntityManager(entityManager);
            return dao;
     }

}

public interface IDAO{
     public void setEntityManager(EntityManager manager);
}

public interface IProdutoDAO extends IDAO{
   //alguns metodos
}

public class ProdutoDAOImpl implements IProdutoDAO{
   // implenta o setEntityManager
}

Todo DAO deve implementar a interface IDAO, para garantir que ele terá o método setEntityManager().

O DaoFactory está implementado de uma forma muito simples. Faça-o como você quiser.

É lógico que este código não é o melhor. É apenas para demostrar uma possível arquitetura para resolver este problema.

aqui se eu tentar colocar @stateless em alguma classe que não tenha uma interface remota como vc fez da o seguinte erro:

Reason: java.lang.RuntimeException: bean class has no local, webservice, or remote interfaces defined and does not implement at least one business interface: LogService

T

Isso porque o EJB mostrado no código NÃO implementa nenhuma das interfaces Local ou Remote, NEM tem seus métodos expostos como webservices. Acredito que o marcelo postou um código com o necessário para o entendimento, somente, sem se atrelar às necessidades do EJB, o que não é necessário. É só fazer a classe de eimplementação do EJB implementar a interface (local ou remota) que vc precisar.

M

ah ta…

pensei que talvez isso que ele postou estivesse de alguma forma funcionando… hehe

K

Eu faria utilizando o Repository Pattern - DDD e acessando os Daos Via IoC , podendo utilizar um projeto como Guice ( google) ou Spring.

Dê uma olhada no Repository , Eric Evans, para conhecer um pouco mais sobre o contexto e o porque da sua utilização. E mais uma coisa, com isso você poderia manter seus DAOS sem ser EJB e levar para outros contextos como a aplicação Standard.

Dois links interessantes :

http://steve.emxsoftware.com/Domain+Driven+Design/DDD+Repositories++Factories - A diferença aqui é que ao invés de utilizar as Factories, vc vai utilizar o approach de IoC para tal.

Curiosidade : uma coisa legal do Guice é o autowiring por annotations :

@ImplementedBy(ServiceImpl.class)
public interface Service {
void go();
}

Se vc não tiver um Wiring explícito, ele utiliza esse default

Bacana pq trabalhar com IoC via annotations pode lhe dar uma excelente produtividade, similar ao projeto SEAM que recomendaram … :slight_smile:

M

exatamente.

C

barluciano:

Cara se vc nao usar @Stateful ou @Stateless em sua classe, o JBoss não vai Injetar o PersistenceContext e vai ficar dando erro de null pointer exception.

@stateful e @stateless são do pacote EJB. Se vc puder dar uma lida em uma das minhas mensagens anteriores vai entender o pq de não poder utilizá-lo ( a maior delas, nesse tópico 12/09/2007 23:58). Não quero ter que escrever aquela mensagem enorme novamente. Não me importo de não haver injeção, desde que possa fazê-lo sem comprometer minha arquitetura.

L

Galera,
Implementei uma solução bem no modelo em que o Marcelo sugeriu, mas o JBoss insiste em me dar essa menssagem:

Ambiente:
JBoss 4.2.1.GA
Netbeans 5.5.1

Estrutura:

Report.ear (Projeto EnterpriseApplication do NetBeans)

-> Report-Business-ejb (Projeto EJB Module do NetBeans)

-ElementoGerenciadoFacade ( como @Stateless )

nesta classe eu tenho um @EJB private DAOFactory daoFactory;

-ElementoGerenciadoFacadeLocal ( como @Local )

-> Report-DAO-ejb (Projeto EJB Module do NetBeans)

- iDAO

- IElementoGerenciadoDAO

- ElementoGerenciadoDAOImpl

- DAOFactory ( como @Stateless )

- persistence.xml
Alguma idéia ?
Criado 13 de novembro de 2006
Ultima resposta 31 de out. de 2007
Respostas 40
Participantes 13