TomCat chamando EJB do JBoss

30 respostas
J

Oi gente, faz umas horas que to tentando aqui e ainda não consegui fazer o tomcat chamar um ejb que está rodando no JBoss

o método que eu estou usarndo para obter a referencia:

meus imports:

import java.util.Properties;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import neg.AcaoRemota;

métodos:

public AcaoRemota getAcaoRemota(String host, String nome) {

        Context jndiContexto = getIntialContext(host);
        Object referencia;
        try {
            referencia = jndiContexto.lookup(nome);

            return (neg.AcaoRemota) PortableRemoteObject.narrow(referencia, neg.AcaoRemota.class);
        } catch (NamingException ex) {
          ex.printStackTrace();
        }
        return null;
    }

    private Context getIntialContext(String host) {
        Properties p = new Properties();
        p.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
        p.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
        p.put(Context.PROVIDER_URL, host);
        try {
            return new javax.naming.InitialContext(p);
        } catch (NamingException ex) {
            System.out.println("Erro ");
            ex.printStackTrace();
            return null;
        }
    }

adicionei os seguintes JARs ao classpath da minha app do tomcat:

jboss-loggin-spi.jar
jbossall-client.jar
jnp-client.jar

mas estou recebendo o seguinte erro ao chamar o metodo getAcaoRemota:

java.lang.ClassCastException: javax.naming.Reference cannot be cast to org.omg.CORBA.Object

at com.sun.corba.se.impl.javax.rmi.PortableRemoteObject.narrow(PortableRemoteObject.java:212)

at javax.rmi.PortableRemoteObject.narrow(PortableRemoteObject.java:137)

at mb.EJBFactory.getAcaoRemota(EJBFactory.java:28)

at mb.MBPrincipal.cadastrar(MBPrincipal.java:30)

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 org.apache.el.parser.AstValue.invoke(AstValue.java:172)

at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:276)

at org.apache.jasper.el.JspMethodExpression.invoke(JspMethodExpression.java:68)

at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88)

at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)

at javax.faces.component.UICommand.broadcast(UICommand.java:387)

at org.ajax4jsf.component.AjaxViewRoot.processEvents(AjaxViewRoot.java:321)

at org.ajax4jsf.component.AjaxViewRoot.broadcastEvents(AjaxViewRoot.java:296)

at org.ajax4jsf.component.AjaxViewRoot.processPhase(AjaxViewRoot.java:253)

at org.ajax4jsf.component.AjaxViewRoot.processApplication(AjaxViewRoot.java:466)

at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:82)

at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100)

at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)

at javax.faces.webapp.FacesServlet.service(FacesServlet.java:265)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)

at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)

at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)

at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)

at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)

at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)

at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)

at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)

at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)

at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)

at java.lang.Thread.run(Thread.java:619)

jah vasculhei o google … e nao consegui achar :frowning:

muita gente tem esse problema mas ninguem dá uma resposta q funcione :frowning:

obs: esse código aí funciona em uma aplicação JavaSE normalmente. :slight_smile:

obrigadoo

30 Respostas

T

Então, duas perguntas:

O jboss e o tomcat estão na mesma maquina?
Caso não estejam, a versão da JVM nessas maquinas é a mesma?

J

sim, estão na mesma máquina

T

Cara, tenta fazer o cast diretamente:

return (neg.AcaoRemota) referencia;

Em EJB3 eu nem uso o narrow.

Qual versao do JBoss vc usa?
O bean é stateful ou stateless?

Abraços.

J

desculpe se eu estiver errado, mas eu acho que vc não viu que eu tambem usei o método narrow

o bean é stateless :slight_smile:

brigado :slight_smile:

T

hehe na verdade vi só no meu segundo post que usava esse método, por isso sugeri que tentasse o cast diretamente.
A proposito, qual a função, alem de cast, desse metodo narrow?

J

po, boa pergunta kkk

depois eu vejo se encontro o que EXATAMENTE ele faz

sempre vi esse trecho como o conjunto da obra kkk sem pensar no todo rsrs

mas facin a gente acha :slight_smile:

e quando ao meu problema? mais alguma ideia?

T

Tenho certeza que o problema é no narrow, a exception diz tudo: cast de tipos diferentes, dai o ClassCastException.
Ainda acho válida a idéia de tentar o cast diretamente.

O que pode estar acontecendo é ter versões diferentes das libs, de repente a implementação mudou bastante de uma para a outra, sei lá, sinceramente agora to chutando =Z

Vou procurar coisas do narrow aqui.

J

ahh tahh foi mal , agora que eu entendi o que vc quis dizer com cast direto kk

vo tenta aki, mas acho q a possibilidade é remota (opa RMI rs) rsrs

T

Olha só, da uma olhada nisso:
http://java.sun.com/j2se/1.4.2/docs/api/javax/rmi/PortableRemoteObject.html#narrow(java.lang.Object,%20java.lang.Class)

E nisso:

http://devgrok.blogspot.com/2009/06/classcastexception-with.html

J

narrow - Checks to ensure that an object of a remote or abstract interface type can be cast to a desired type.

parece q é um instanceof :S talvez um instanceof++

T

javando:
narrow - Checks to ensure that an object of a remote or abstract interface type can be cast to a desired type.

parece q é um instanceof :S talvez um instanceof++


Foi exatamente o que pensei, antes de dar um cast ele testa com instanceof.
Mas que diferença faz se da o ClassCastException do mesmo jeito? huauhauhauhaa

ps: adorei aquela piada da possibilidade remota (RMI) UAUHAuhAHUAUHa isso é que é começar bem o ano hahahha.
ps2: definitivamente esse não é o tipo de piada que contarei aqui em casa =(

J

pelo o q eu entendi o cara tah dizendo que usando esse metodo manual pode ser que o cliente chame um ejb 3 esperando que seja um ejb 2

e ele fez uma bela duma gambi rsrs pra poder chamar um ejb 3 com esse metodo …

esse problema não ocorre quando o ejb é injetado via @EJB

mas eu nao consegui usar essa anotation na aplicação do tomcat

J

deve ter um jeito mais decente de chamar um ejb no tomcat

até mesmo sem usar essas coisas feias ai, de lookup narrow e afins … só resta saber como rsrs

T

E o cast direto? :smiley:

Precisa mesmo do narrow?

J

putz, tava vendo uns baralho aki kkk esqci do cast kk

vo testa

J

me retornou asim:

java.lang.ClassCastException: javax.naming.Reference cannot be cast to neg.AcaoRemota

ou seja,
a linha

referencia = jndiContexto.lookup(nome);

colocou na referencia um objeto javax.naming.Reference e nao um objeto AcaoRemota

o narrow deve fazer a conversão da referencia em objeto ai a gente pega esse objeto e dah o cast, como ta la

B
Creio que esta exceção ocorreu porque o container não conseguiu localizar seu proxy stub, por isso tentou fazer um cast para Corba Object pelo fato de vc estar usando uma inteface remota.... 
Quando vc subir sua aplicação no jboss vc pode acessar o jmx-console e verificar se o seu bean de sessão está associado a um nome no link JNDIView...

Creio que esta exceção ocorreu porque o container não conseguiu localizar seu proxy stub, por isso tentou fazer um cast para Corba Object pelo fato de vc estar usando uma inteface remota…
Quando vc subir sua aplicação no jboss vc pode acessar o jmx-console e verificar se o seu bean de sessão está associado a um nome no link JNDIView…

J

breno500as:
java.lang.ClassCastException: javax.naming.Reference cannot be cast to org.omg.CORBA.Object

Creio que esta exceção ocorreu porque o container não conseguiu localizar seu proxy stub, por isso tentou fazer um cast para Corba Object pelo fato de vc estar usando uma inteface remota…
Quando vc subir sua aplicação no jboss vc pode acessar o jmx-console e verificar se o seu bean de sessão está associado a um nome no link JNDIView…

sim, está la registrado tanto é que a minha aplicação javaSE acessa

B

Em vez de usar o Portable faz assim então:

Se o seu bean estiver registrado corretamente não vai dar erro… Mas creio que vc vai ver que sua exceção vai mudar para algo parecido com isso aqui:

J

eu jah havia tentado isso, mas por via das duvidas fiz de novo

deu o seguinte:

java.lang.ClassCastException: javax.naming.Reference cannot be cast to neg.AcaoRemota

precisa usar o narrow não tem como eu acho

B

Seu cliente JSE está rodando em qual container??? No jboss né?

J

meu cliente jse nao tah rodando em container nenhum

eu rodo ocmo qualquer aplicação jse, o jboss, glassfish e afins nem sabe q essa apkicação existe rsrs só respondem aos pedidos dela :slight_smile:

valeu

B

aff… vacilo meu, é verdade… são quase 3:00 da manã to quase dormindo aqui no pc…kkkk…

Mas a respeito do erro do classCast se vc der um F5 e debugar para ver o que acontece no narrow fica fácil de enteder… da uma olhada no que ele faz:

PortableRemoteObject.narrow(referencia, neg.AcaoRemota.class);
public java.lang.Object narrow ( java.lang.Object narrowFrom, 
	java.lang.Class narrowTo) throws ClassCastException 
    {
        java.lang.Object result = null;

        if (narrowFrom == null)
            return null;

        if (narrowTo == null) 
            throw new NullPointerException("invalid argument");

        try { 
            if (narrowTo.isAssignableFrom(narrowFrom.getClass())) 
                return narrowFrom;

	    // Is narrowTo an interface that might be
	    // implemented by a servant running on iiop?
	    if (narrowTo.isInterface() && 
		narrowTo != java.io.Serializable.class &&
		narrowTo != java.io.Externalizable.class) {
	
		org.omg.CORBA.Object narrowObj 
		    = (org.omg.CORBA.Object) narrowFrom;                
		
		// Create an id from the narrowTo type...
		String id = RepositoryId.createForAnyType(narrowTo);
		
		if (narrowObj._is_a(id)) {
		    return Utility.loadStub(narrowObj,narrowTo);
		} else {
		    throw new ClassCastException( "Object is not of remote type " +
			narrowTo.getName() ) ;
		}
	    } else {
		throw new ClassCastException( "Class " + narrowTo.getName() + 
		    " is not a valid remote interface" ) ;
	    }
        } catch(Exception error) {
	    ClassCastException cce = new ClassCastException() ;
	    cce.initCause( error ) ;
	    throw cce ;
        }
    }

narrowFrom é o seu objeto referencia que neste caso é um NamingContext (aqui é onde esta o erro pois na verdade o que deveria estar aqui é o seu proxy stub e não o NamingContext ), narrowTo é o seu AcaoRemota…

Se estivesse tudo certo o método retornaria o narrowFrom no if da linha 13 mas como NamingContext não é um subtipo nem um tipo da sua AcaoRemota ele passa por este if e tenta dar um cast para org.omg.CORBA.Object na linha 22 dando o classCastException…

J

realmente, bem abservado,

eu fiz o debug da aplicação rodando no jboss e realmente ele entra no IF

mas pq no tomcat nao entra?, a versão da interface é a mesma :S

B

Então kara…como tinha te falado no primeiro post de alguma forma seu proxy stub não está sendo localizado…

Provavelmente no tomcat o nome que vc pesquisa na jndi é diferente da forma que vc faz no jboss ou na sua aplicação JSE…

É meio complicado mas vc vai ter que ir fazendo tentativas nessa linha abaixo para retornar um proxy stub e não um NamingContext

referencia = jndiContexto.lookup(nome);

Na variável nome tente pelo nome totalmente qualificado(pacote, classe,método),ou pelo nome absoluto(java:comp/env/NomeDoSeuBean/remote) ou pelo nome do contexto + o nome do bean (NomeDoContextoDaSuaAplicaçãoEJB/NomeDoSeuBean/remote)… ou outras formas…

W

Cara, pode ser que esse não seja exatamente o problema aí, mas o narrow é totalmente inútil se você está usando somente EJB3.

J

Cara, pode ser que esse não seja exatamente o problema aí, mas o narrow é totalmente inútil se você está usando somente EJB3.

é, estive vendo um artigo da sun e mostrou isso mesmo :S

mas no livro Enterprise JavaBeans 3.0 mostra usando assim, aí eu acabei fazendo dessa forma

T

Mas então, conseguiu fazer funcionar com o lookup direto?

Abraços.

J

cara
eu nao consegui ainda

tah muito triste a situação :S

só pra mim dar uma distraída eu tentei implantar o ejb no glassfish, pra ver se eu acessava do tomcat

affe … piorei a situaçao

ALGUEM POR FAVORRRR explica um negócio, diz a documentação que eu tenho q por no meu classpath um arquivo chamado appserv-rt.jar que se encontra na pasta lib do glassfish, mas, esse arquivo tem 3K e NAO TEM nenhuma classe dentro dele :S e manda tambem botar no classpath do cliente um arquivo chamado javaee.jar que tambem tem 3K e nenhuma classe.

o pior é que quando roda o cliente, ele reclama das classes que estariam nesses jars, mais porq raios que esses meus jars estao vazios? eu baixei hoje o glassfish, nem tah zuado as pastas :S

A

Pessoal,

Passei por um problema semelhante e descobri a solução. Talvez também se aplique neste caso. Este é código que uso para fazer o lookup e invocar um método no objeto remoto EJB 3.0 a partir de duas aplicações clientes distintas:

final Properties props = new Properties();
props.put("java.naming.factory.initial", "org.jboss.naming.NamingContextFactory");
props.put("java.naming.provider.url", "jnp://localhost:2099");
props.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");

final Context initial = new InitialContext(props);
final SismService service = (SismService) initial.lookup("my-name/remote-sgbds.SismService");
System.out.println(service.getStringLength("Angelo"));

A primeira aplicação é uma aplicação J2SE convencional onde tudo funciona perfeitamente. A segunda é uma aplicação que roda em um contexto meio enrolado de explicar, mas cuja a execução gerava a seguinte exceção:

O que estava acontecendo era o seguinte: o método lookup em determinado momento obtém um objeto do tipo javax.naming.Reference. Este objeto é uma referência para o objeto EJB remoto e contém, além do endereço para alcançar o objeto remoto, o nome de uma classe factory capaz de construir um proxy para conversar com o objeto remoto. Para instanciar um objeto factory adequado, o método lookup primeiramente carregará na máquina virtual a classe cujo nome foi obtido do Reference.

No meu caso, o nome da classe era org.jboss.ejb3.proxy.impl.objectfactory.session.stateless.StatelessSessionProxyObjectFactory (pode ser obtido inspecionando-se o objeto Reference na IDE). O método lookup não estava encontrando esta classe no classpath e ao invés de criar um proxy, simplesmente retornava o objeto Reference, causando a cast exception.

A carga desta classe factory é feita em tempo de execução, por reflexão. Ou seja, o código da aplicação compila perfeitamente, embora possam existir classes que não estão no seu classpath e serão necessárias mais tarde. Para garantir que as classes necessárias sejam encontradas, o arquivo jbossall-client.jar tem que estar no classpath das aplicações clientes.

Eu havia colocado este arquivo no classpath das duas aplicações cliente, mas uma delas insistia em continuar sem funcionar. A causa do problema é que no meu “ambiente estranho”, são utilizados dois class loaders distintos. Um responsável pela carga de classes “de sistema” (pacotes java, javax, etc) e outro por classes de propósito específico. Um deles tinha acesso as classes de jbossall-client.jar e o outro não. No caso do colega javando, que está tendo problemas com uma aplicação cliente rodando dentro do Tomcat, a causa do problema pode ser a mesma, pois o Tomcat também utiliza vários class loaders (http://tomcat.apache.org/tomcat-6.0-doc/class-loader-howto.html).

Minha hipótese para o problema do fórum: Talvez, o class loader do Tomcat que precisa enxergar as classes do jbossall-client.jar não esteja conseguindo. Provavelmente, o arquivo jbossall-client.jar está listado dentre as bibliotecas da aplicação web, mas não nas bibliotecas “gerais do container”. Quando o class loader da aplicação detecta a necessidade de instanciar javax.naming.InitialContext, delega a tarefa para o class loader geral (pois javax pode ser visto como um recurso de sistema). Mas este class loader geral não enxerga as bibliotecas do class loader filho e falha ao tentar instanciar a classe factory por reflexão.

Abraços,
Ângelo

P.S.: Outro detalhe: observe que o arquivo jbossall-client.jar contém apenas um diretório META-INF contendo um MANIFEST gigante, responsável por listar todas os demais jars do cliente jboss facilitando o trabalho de deploy em alguns casos. Apenas colocar este cara dentro do classpath de uma aplicação sem garantir que todas os demais jars referenciados estão acessíveis pode não ser suficiente!!!

Criado 1 de janeiro de 2010
Ultima resposta 15 de mai. de 2012
Respostas 30
Participantes 5