Re:EJB 3.0 + Jboss AS 4.2 + Web Tier = ClassCastException

4 respostas
rodrigo.ferreira

Bom dia, tudo bem?

Tente fazer o ServiceLocator assim:

package br.suaaplicacao.util;

    import javax.naming.Context;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;

    public class ServiceLocator {

	private Object objetoRetorno = null;
	
	public static Object getEjb(String jndiName) {
		
		try {
			
			Context ctx = new InitialContext();
			objetoRetorno = ctx.lookup(jndiName);
			
		} catch (NamingException e) {
			throw new RuntimeException(e);
		}
		
		return objetoRetorno;
		
	}
	
    }

Chame o service locator assim:

// Aqui nós vamos criar uma referência e fazer o cast no objeto retornado do Service Locator. Assim, o service locator fica realmente genérico e útil.
    // Podemos usar o ServiceLocator assim para qualquer lookup, de qualquer objeto que precisarmos.

    CatalogManager bean = (CatalogManager) ServiceLocator.getEjb(CatalogManager.class.getCanonicalName());  // ou o nome JNDI mapeado
   
    // depois execute o método da interface

    List<Product> listaProduto = bean.listAll();

Fazendo o ServiceLocator mais genérico é menos sucetível a erros de Cast.

Pelas boas práticas, você deve fazer o Cast depois de obter a referência remota. Assim, você evita erros e aplica corretamente o Sun J2EE Design Pattern Service Locator. (http://java.sun.com/blueprints/corej2eepatterns/Patterns/ServiceLocator.html)

Tenta fazer assim. Acho que vai resolver o seu problema.

Abraço,

Visite o Blog do Perereca: http://www.blogdoperereca.blogspot.com

4 Respostas

rodrigo.ferreira

Opa, beleza então!! :slight_smile:

Abraço,

Visite o Blog do Perereca: http://www.blogdoperereca.blogspot.com

theBalrog

Pessoal,

Já procurei bastante, nos fóruns do JBoss, o moderador até falou pra um camarada que está com essa mesma dúvida que esse problema já foi discutido em outro tópico, e fechou o mesmo sem indicações de onde foi discutido. Aqui também procurei, provavelmente já foi discutido, mas não encontrei...

Estou tendo meus primeiros contatos com EJB recentemente e tenho feito os tutoriais do JBoss. EJB3, diga-se de passagem.

Pois bem, fiz os tutorias de Session Beans, tendo como client uma aplicação void main para testar. Perfeito até aqui. Estou gostando bastante de EJB.

No entanto, pensei: "preciso fazer um teste de EJB com uma aplicação WEB, que é o meu campo de atuação".

Fiz então um Stateless Session Bean para listar todos os produtos disponíveis em um catálogo (esse é o conceito, basicamente é uma lista estática de produtos, só pra testar).

Fiz um Service Locator da seguinte forma, que são acionados pela Servlet:
public static <Bean> Bean getBean(Class<Bean> klass) {
        try {
            InitialContext context = new InitialContext();
            return((Bean) context.lookup(klass.getSimpleName() + "Bean/remote"));
        }
        catch(NamingException e) {
            throw(new RuntimeException(e.getMessage(), e));
        }
    }
Utilizo-o da seguinte forma:
CatalogManager bean = ServiceLocator.getBean(CatalogManager.class);
Sendo que CatalogManager é a interface @Remote. Essa chamada retorna um proxy para meu bean abaixo:
@Stateless
public class CatalogManagerBean implements CatalogManager {
    public List<Product> listAll() {
        return(Catalog.CATALOG);
    }
}
Essa estrutura funciona perfeitamente. Meu próximo passo foi fazer o famoso carrinho de compras, Stateful, seguindo o tutorial do JBoss. A interface remota e o bean, como a seguir:
@Remote
public interface ShoppingChart {
    void add(Product p, int quantity);

    List<ChartItem> listItems();
}

@Stateful
public class ShoppingChartBean implements ShoppingChart, Serializable {
    private static final long serialVersionUID = -8529946335150567438L;

    private List<ChartItem>   chart            = new ArrayList<ChartItem>();

    public void add(Product p, int quantity) {
        ChartItem item = this.findItem(p);

        item.setQuantity(quantity + item.getQuantity());
    }

    public List<ChartItem> listItems() {
        return(this.chart);
    }

    private ChartItem findItem(Product p) {
        ChartItem item;
        int index = this.chart.indexOf(p);

        if(index == -1) {
            item = new ChartItem();

            item.setProduct(p);
            this.chart.add(item);
        }
        else {
            item = this.chart.get(index);
        }

        return(item);
    }
}

Sem mistérios até aqui. Tudo absolutamente comum.
No que eu fui testar a aplicação:

java.lang.ClassCastException: $Proxy69

Esse erro ocorreu logo após eu dar um getBean em meu ServiceLocator. Debugando calmamente, descobri que esse proxy não é uma instância da minha interface remota. Como é possível.

Li em algum lugar que o AS que eu faço deploy dos meus EJB's não pode ser o mesmo que o AS que está a aplicação, isto é, não pode ser a mesma VM. Isso até faz sentido porque fiz um main() pra testar esse bean de carrinho de compras e funcionou liso.

Alguma orientação de quem entende disso?

Obrigado pessoal!

theBalrog

Acabei de ver que existe a versão 5.0.1 GA do JBoss.

Fiz o download e instalei nessa versão meu pacote de EJBs e minha aplicação, no estado atual.

Funcionou perfeitamente. É possível que seja bug na versão 4.2 do nosso AS?

theBalrog

Fala Rodrigo.

Bem, o problema não é meu código cara. Como eu disse no post anterior, mudei para o JBoss 5.0 e está tudo bem. Perfeitamente como planejado.
E curiosamente tive a oportunidade de falar informalmente com um profissional da Red Hat e comentei isso pra ele, a cara que ele fez quando falei disso foi algo do tipo: “você fez bem em atualizar para o JBoss 5” rsssss

Sobre o pattern, eu sei que o casting deve ser feito após a chamada do meu ServiceLocator. Mas estamos falando de preciosismo conceitual, o que sabemos (eu, pelo menos) que na prática não funciona; temos que trabalhar e usar do que dispomos para fazer o trabalho da melhor forma possível. Se a utilização de um pattern pode complicar minha vida, não tenha dúvidas que vou adaptá-lo.

Um grande abraço cara, e obrigado pela ajuda.

Criado 13 de maio de 2009
Ultima resposta 13 de mai. de 2009
Respostas 4
Participantes 2