Lookup de EJB 3.0 Remoto

42 respostas
D

Fiz deploy de um EJB 3.0 Session Bean Stateless no JBoss 4.0.4-GA como um pacote JAR e consigo fazer o lookup remoto (outra JVM) numa boa, somente pelo nome da classe.

Agora, se eu faço o deploy do EJB dentro de um pacote EAR, ele não acha mais o EJB (name not bound).

Alguma dica?

42 Respostas

P

Destro, o ejb3 deployer binda o ejb com um endereço do tipo

ear-name/bean-name/remote

Não seria isso?

D

Um beijo na boca… Funcionou!

Mas, putz… ter que colocar o nome do EAR mata… não tem como evitar isso?

Pois terei delegates rodando em outras VMs, remotamente. E também quero depender do nome do EAR.

P

Ter, tem. Tu poderia usar as anotações @RemoteBinding e @LocalBinding, pra garantir que o seus EJBs vão manter os mesmos endereços JNDI, independente de como eles foram empacotados.

D

Assim fico preso ao JBoss. Não queria isso.

P

O problema é que JEE/EJB nunca definiu como um componente deveria ser bindado no JNDI. Ou seja, mesmo se tu encontrar uma configuração do Jboss para que ele binde da mesma forma, sendo local ou remote, se você colocar no XPTO aplication server, ele pode bindar da forma que quizer, e lá se vai tua liberdade.

E pior, não acho que isso vai mudar tãooo cedo.

D

Que droga!

No meu Bean eu fiz:

Porém, quando eu faço o lookup remoto:

Ele me dá a mensagem de erro:

Ou seja, ele ignora no que vem a partir da barra (’/’). Porque será?

P

Estranho Daniel…Testou colocar lookup por outra string qualquer para ver se não ocorre um problema parecido?

D

Tentei, mas também deu problema.

Asim funcionou:

Ficou mais complicado isso.

P

Btw, uma dúvida destro: porque você não está usando os recursos de dependency injection do JEE 5?

@EJB(beanName="nome_ear/CadastroUsuario/remote") protected CadastroUsuario cadastroUsuario;

D

Porque meu Delegate (E ServiceLocator) fica remotamente e a idéia é que este EJB (Session Façade) seja um serviço.

Se fosse a mesma app (web/ejb) faria sentido.

D

plentz:
Destro, o ejb3 deployer binda o ejb com um endereço do tipo

ear-name/bean-name/remote

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

W

a resposta =(

http://wiki.jboss.org/wiki/Wiki.jsp?page=Ejb3Jndi

se alguém achar algo mais simples me avisem, please.

D

Bom, a Sun mudou bastante a especificação dos EJBs, e do JavaEE, porém esqueceu ou deixou a desejar em detalhes simples e triviais.

Isso irrita!

A

Cara, algum de vocês dois pode me ajudar?

Olá, pessoal!

Já conheço o EJB 2.1 e agora estou estudando o 3.0.
Baixei o NetBeans 5.5 beta 2 com o Glassfish.
Fiz uma aplicação simples - e depois testei um dos exemplos
embutidos no NetBeans - com um EJB Stateless, mas o cliente
não consegue acessar o EJB: recebo uma NullPointerException ao
tentar usar a referência para o meu SessionBean, que, teoricamente,
não estaria Null devido à Injeção de Dependência.

Irei mostrar o código cliente, que é bastante simples:

public class Login {
   
    @EJB
    private static LoginRemote loginRemote;
   
    public static void main(String args[]) {
        Login login = new Login();
        String test = new String("thyago");
        login.callMeth(test);
    }
   
    public void callMeth(String teste) {
        try {
            System.out.println("Trying to log in the system...");
            loginRemote.login(teste);
        } catch (Exception e) {
            e.printStackTrace();
        }
    } 
}

Depois de fazer o deploy, eu executo o código cliente e recebo uma NullPointer no “loginRemote.login(teste)”. Repito que a própria aplicação do NetBeans também lançou um NullPointer.

Alguém pode me ajudar?
Obrigado =]

D

A DI é feita dentro do próprio container JEE, não fora dele.

A

E o que eu precisaria alterar para poder chamar o EJB em um sistema Desktop? Eu estou deployando e executando a classe.

D

Properties env = new Properties(); // .. configure o 'env' para acessar o EJB remotamente Context ctx = new InitialContext( env ); SeuAmigo amigo = (SeuAmigo) ctx.lookup("nome_ear/SeuAmigo/remote"); amigo.digaOi();

A

Opa, Daniel!

Cara, brigado pela ajuda! Eu fiz isso ae em um computador na faculdade e funcionou, mas quando cheguei em casa e repeti o mesmo código o JBoss lança uma exceção:

Exception in thread "main" java.lang.NoClassDefFoundError: [Lorg/jboss/aop/advice/Interceptor;
        at java.lang.Class.getDeclaredFields0(Native Method)
        at java.lang.Class.privateGetDeclaredFields(Class.java:2259)
        at java.lang.Class.getDeclaredField(Class.java:1852)
        at java.io.ObjectStreamClass.getDeclaredSUID(ObjectStreamClass.java:1582)
        at java.io.ObjectStreamClass.access$700(ObjectStreamClass.java:52)
        at java.io.ObjectStreamClass$2.run(ObjectStreamClass.java:408)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.io.ObjectStreamClass.<init>(ObjectStreamClass.java:400)
        at java.io.ObjectStreamClass.lookup(ObjectStreamClass.java:297)
        at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:531)
        at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1552)
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1466)
        at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1552)
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1466)
        at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1552)
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1466)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1699)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1305)
        at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1908)
        at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1832)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1719)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1305)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:348)
        at java.rmi.MarshalledObject.get(MarshalledObject.java:135)
        at org.jnp.interfaces.MarshalledValuePair.get(MarshalledValuePair.java:72)
        at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:652)
        at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:587)
        at javax.naming.InitialContext.lookup(InitialContext.java:351)
        at teste.HelloCliente.main(HelloCliente.java:31)

Ce sabe o que pode ser isso?

E, só pra ilustrar o jeito como funcionou:

public static void main(String args[]) {
        
        try {
            Hashtable prop = new Hashtable();
            prop.put(InitialContext.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
            prop.put(InitialContext.PROVIDER_URL, "jnp://localhost:1099");
            
            Context ctx = new InitialContext(prop);
            
            Object obj = ctx.lookup("HelloBean/remote");
            
            HelloRemote hello = (HelloRemote) obj;
            
            hello.sayHello();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
A

Opa! Deu tudo certo, Daniel, muito obrigado, cara!

D

O que faltava que dava este erro? Um JAR do JBoss no client?

A

Exato. Há um JAR que eu não lembro bem o nome, mas acho que tem “aop” no meio. Bastou inclui-lo que o erro sumiu =]

Cara, como eu faço pra usar ID em um arquivo java executável (com um método main)?

Estou perguntando por que programo da seguinte maneira: crio as classes na IDE, deplos executo o servidor, faço o deploy e executo a classe main à partir da IDE depois do deploy. O que eu acho que acontece é que, através da JNDI, a classe consegue encontrar o bean que eu solicitei e o executa - e como ele executa na IDE, não há como utilizar ID, como você disse anteriormente.

Mas como eu utilizo o @EJB em uma classe com um método main?

Obrigado =]

D

ID? Que ID?

Sobre o @EJB, creio que só dentro do próprio container. Não sei se há uma maneira de configurar para ele injetar recursos de um container remoto.

A

Injeção de Dependência
Devia ter falado, foi mal =]

Será que se eu deployar o JAR e executar com “java -jar …” a ID funciona?

D

Não funciona…

Quando você executa um programa stand-alone (que contém o main), você não tem as funcionalidades implementadas do container, a não ser que use as configurações (por exemplo do Spring).

R

Daniel, acho que deve ter uma maneira de usar @EJB remotamente. O próprio exemplo da Sun tem o seguinte código:

package enterprise.security_stateless_appclient;

import javax.ejb.EJB;
import enterprise.security_stateless_ejb.Sless;

public class SlessAppClient {
    @EJB private static Sless sless;

    public static void main(String args[]) {
        System.out.println(sless.helloRolesAllowed());

        try {
             sless.helloRolesAllowed2();
             throw new IllegalStateException(
                 "Unexpected succesful call for helloRolesAllowed2()");
        } catch(Exception ex) {
             System.out.println("Expected Exception for sless.helloRolesAllowed2()");
        }

        System.out.println(sless.helloPermitAll());

        try {
             sless.helloDenyAll();
             throw new IllegalStateException(
                 "Unexpected succesful call for helloDenyAll()");
        } catch(Exception ex) {
             System.out.println("Expected Exception for sless.helloDenyAll()");
        }
    }
}

Fonte:
http://java.sun.com/javaee/reference/code/

Já ví outros exemplos usando @EJB remotamente. Estou correndo atrás disso também se achar a resposta mando aqui…

R

Já achei. O Jboss não fornece um client container.

http://www.jboss.com/index.html?module=bb&op=viewtopic&t=86803

Estou seriamente tentado a migrar para o GlassFish. Ele suporta o client container. Alguém já está usando o GlassFish? Só fico preocupado se ele não tiver ferramenta para o Eclipse.

Abraços!

A

Eita… isso realmente responde tudo.
Eu vou tentar rodar no GlassFish também.
Como eu não uso o Eclipse não vou me preocupar com isso =D
Mas se não tiver suporte direto para o Eclipse, roda um Ant! =P

E obrigado a todos! :smiley:

D

E aquela parada do JBoss rodar EJB 3.0 fora do container? Não resolve?

R

Acho que isso não o transforma em um “Client Container”, já que uma das premissas dele é ser “lightweight”.

E outra, carregar um Embeddable JBoss pra dentro dos meus clientes que são Swing é um pouco demais.

É uma falta grave da comunidade JBoss não investir num “Client Container”. Spring e Glassfish saem na frente…

R

O que eu tento fazer e nunca dá certo, sempre dá nullpointexception:

No netbeans eu tenho 2 projetos. 1 EJB3 (CalcEJB) e 1 Cliente (CalcCliente)

Crio um simples beans stateless chamado Calc e implemento as interfaces remote e local com o método int soma(int a, int b).

No projeto cliente eu chamo o EJB:
@EJB
private static …remote …

Tenho um JFrame com 3 edits e 1 botão, os dois edits passam os inteiros e o terceiro edit teoricamente recebe o resoltado, o botão chama o método:
remote.soma(…)

Rodo o glassfish e faço o deploy dos 2 projetos

Quando executo o cliente sempre dá um NullPointException

Lí em vários tutoriais que o EJB3 dispensa o uso de lookups. Alguém sabe como posso resolver isso. Indicar algum tutorial?

Obrigado.

A

Pois então Rodrigo, essa foi exatamente a dúvida que eu cheguei nesse fórum com. Eu também li que o EJB3 dispensava o uso de lookups, mas não funcionou de jeito nenhum. O lookup tá bem mais simples, não precisa mais de um home e nem de um “narrow”, mas eu ainda tow precisando fazer o lookup.

O que o daniel falou me acordou pra um fato: se eu estou usando o netbeans, faço o deploy e depois executo um arquivo main NO NETBEANS utilizando @EJB, este arquivo não está sendo executado dentro do container, logo não pode receber a instância do bean por injeção. Dai eu me perguntei “e como diabos ele conseguiria usar a injeção de dependencia do container no cliente?”. Dai o pessoal veio com a resposta de que o JBoss - o que eu tow usando - não tem Client Container.

Tá meio nebuloso ainda pra mim =]

R

Então eu só posso usar dependence injection se o AS tiver client container? Mas o glassfish já não tem isso? Pq não funciona? É meio confuso mesmo.

Obrigado.

D

É simples. Dependency Injection (DI) só funciona dentro do container que implementa a especificação EJB 3.0.

Fora do container, não tem um mecanismo padrão que já faça isso, portanto é necessário usar algum recurso que permita isso, por exemplo esse tal de Client Container que tem no Glassfish. Porém é necessário que isto seja configurado e utilizado na sua aplicação. Do nada isso não funciona mesmo.

É como tentar fazer conexão ao BD sem usar um driver apropriado. Énecessário prover a implementação de acesso ao BD para funcionar.

Com a DI é a mesma coisa. Tem de existir uma implementação que faça isso funcionar.

R

Entendi, notei que no glassfish só posso rodar a aplicação cliente swing por um link usando JWS, acho que é assim que ele implementa o cliente container.

Realmente se vc for parar para pensar, como uma aplicação swing normal vai saber qual o endereço da máquina do servidor de aplicação? Não tem como, só com jws mesmo.

Archon, vc poderia me mandar um projeto de exemplo no netbeans usando DI, mesmo que seja o JBoss?

R

Se você executar o cliente na mesma máquina em que está o servidor Glassfish, use o comando appclient -client <AplicacaoCliente.jar>.

Se for executar remotamente, é possível obter o Client Container através do comando package-appclient . Daí, é só extrair o conteúdo do appclient.jar e configurar alguns arquivos.

Links sobre o assunto que achei interessantes:
http://blogs.sun.com/pblaha/entry/ejb_3_0_client_in
http://docs.sun.com/source/817-6092/hman1m/appclient.1m.html
http://docs.sun.com/source/817-6092/hman1m/package-appclient.1m.html
http://docs.sun.com/app/docs/coll/134.4

Isso ajudou?

No entanto, estou tendo problemas para executar qualquer cliente remoto que lide com transações. Consigo criar os Entity Beans, mas na hora em que chamo sessionBean.create(myEntityBean), por exemplo, ele lança uma excessão.

Vai saber…

R

Se bem que quando utiliza -retrieve ele volta toda a aplicação, não apenas as classes do cliente e os ejb’s com os quais se relaciona, como, por exemplo, a implementação de um Business Delegate.

Tem que ter um jeito de voltar só o essencial…

R

Esse forum é demais… vcs detonaram o EJB… ou quase no meu caso !!

Seguinte tenho um EJB3 rodando, com um método lá… coisa simples…
quando tendo chamar ele de uma aplicação web (struts,tiles,jsp,etc…) a partir da action… testeEjb.

public String testeEjb() throws Exception {

		Properties properties = new Properties();
 		properties.put("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
 		properties.put("java.naming.factory.url.pkgs","=org.jboss.naming:org.jnp.interfaces");
		properties.put("java.naming.provider.url","localhost:1099");
 			
		Context context = new InitialContext(properties);
		
		Object home = context.lookup("ConsultaCEPBean/remote");
		
				

		System.out.println(context.lookup("ConsultaCEPBean/remote"));
		System.out.println("teste");
		
		return SUCCESS;
	}

A pergunta é a seguinte como eu executo os métodos que estam dentro do
objeto home?
Object home = context.lookup(“ConsultaCEPBean/remote”);

Se tiver outra forma, me avisa…

desde já obrigado !!!

D

EJB 3 não tem interface home.

R

Srs;

Estou tendo um problema aqui e desconfio do seguinte:

Estou fazendo um EJB com o Hibernate sem Anotations, ou seja com o mapeamento feito via xml e esta retornado uma série Exception. A dúvida é, será que isso ocorre porque o Hibernate com EJB3 deve-se usar Anotations?

Desde já obrigado !

L
Salve pessoal,

Tenho um session bean dentro de um jar e essse jar dentro de um ear no JBoss 4.0.5.

Quero acessar esse bean a partir de um cliente remoto.

Já tentei fazer o lookup da seguinte maneira:

bean contendo:
@Stateless
public static final String JNDIname = ServiceProviderBean.class.getSimpleName() + “/remote”;

cliente fazendo lookup:
lookup(ServiceProviderBean.JDNIname);

bean contendo:
@Stateless
@RemoteBinding(jndiBinding=“br.com.xyz.services.provider.ServiceProviderBean”)

cliente fazendo lookup:
lookup(“ServiceProviderBean/remote”);

bean contendo:
@Stateless
@EJB(name=“sp”, beanInterface=ServiceProvider.class)

cliente fazendo lookup:
lookup(“java:/comp/env/sp”)

bean contendo:
@Stateless

cliente fazendo lookup:
lookup(“java:/comp/env/br.com.xyz.services.provider.ServiceProviderBean”);

e nada funcionou.

Só funcionou assim:

bean contendo:
@Stateless

cliente fazendo lookup:
lookup("//remote").

…porém, não quero usar esse lookup, para não ter que passar o nome do ear.

Como estou usando EJB3 e ele não necessita de ejb-jar.xml, o que está faltando para funcionar? Alguém poderia me dar um luz?

Agradeço desde já qualquer colaboração.

[]s,

Luiz

R

Boa tarde…

estou tendo o mesmo problema de só conseguir fazer o lookup no ejb3 utilizando lookup("//remote").

Alguem sabe como eu posso fazer isso sem utilizar o nome do ear.

Obrigado

T

Ai pessoal, vou colocar algumas coisas que usamos para acesso remoto de EJBS.

Fixture para acesso:

public class ServiceLocator {
	private Context context;

	public ServiceLocator(Context context) {
		this.context = context;
	}

	public ServiceLocator(Server server) throws NamingException {
		context = new InitialContext(JndiPropertiesBuilder.build(server));
	}

	/**
	 * Method responsible for fetching an instance of an EJB. Makes a lookup, if
	 * not found returns null
	 * 
	 * @param ejb
	 * @return
	 */
	public <T> Object lookup(Class<T> ejb) {
		try {
			Object lookup = context.lookup(ejb.getSimpleName() + "-remote");
			return lookup;

		} catch (NamingException e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * Method responsible for fetching an instance of a remote service from a
	 * server selected by the manufacturer.
	 * 
	 * @param serviceRemoteBean
	 * @return
	 */
	public <T> Object getRemoteService(Class<T> serviceRemoteBean) {
		return lookup(serviceRemoteBean);
	}
}

public class JndiPropertiesBuilder {

	private JndiPropertiesBuilder() {
		// should not be instantiated.
	}

	public static Properties build(Server server) {
		Properties properties = new Properties();

		properties.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
		properties.put("java.naming.provider.url", server.getJndiName());
		properties.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");

		return properties;
	}
}

public enum Server {

	SELENIUM("http://URL_SERVER", "jnp://IP:1099");
	
	private String url;
	private String jndiName;
	
	private Server(String url, String jndiName) {
		this.url = url;
		this.jndiName = jndiName;
	}
	
	
	public String getUrl(){
		return this.url;
	}
	
	public String getJndiName(){
		return this.jndiName;
	}
}

O seu Bean remoto deve ser anotado da seguinte maneira:
@Stateless(mappedName = “ServiceBean-remote”)

O restante são as dependencias. Importante lembrar que esse exemplo é para Jboss 6x!
Abraço a todos.

Criado 20 de setembro de 2006
Ultima resposta 22 de nov. de 2012
Respostas 42
Participantes 11