martes, 4 de mayo de 2010

Cliente remoto de EJB 3.1 (en GlassFish V3)

  19 comentarios
Leyendo el FAQ de EJB (https://glassfish.dev.java.net/javaee5/ejb/EJB_FAQ.html) quiero comentar cómo crear un cliente EJB sin necesidad de desplegarlo en el mismo en servidor. Realmente es muy simple:


1. Crear el Módulo EJB.

Creo que esta opción es demasiada fácil. En resumen, he creado un módulo llamado CalculadoraEJBModule. Este nombre es importante que lo utilizaremos al final en el cliente. Este módulo tiene la interfaz remota del ejb ejb.CalculadoraBeanRemote y su implementación ejb.CalculadoraBean
Aquí la interfaz:
package ejb;
import javax.ejb.Remote;

@Remote
public interface CalculadoraBeanRemote {

    long factorial(long num);
    
}

y aquí la implementación:
package ejb;

import javax.ejb.Stateless;

@Stateless
public class CalculadoraBean implements CalculadoraBeanRemote {

    @Override
    public long factorial(long num) {
        if (num < 1) {
            return 1L;
        }
        return factorial(num - 1) * num;
    }
}


2. Desplegar el módulo

Nada más que hacer "deploy" al módulo desde el NetBeans, y listo, ya está publicado en nuestro servidor (por ahora en el local)

3. Hacer una aplicación Java común

Notar que no estoy mencionando hacer una cliente EJB de Java. No. En este caso haremos una aplicación común Java, como si fuera un Swing, o de consola. Nada más. Para nuestro ejemplo lo llamaremos CalculadoraCliente. Y la clase Main tendrá el siguiente código:
package calculadoracliente;

import ejb.CalculadoraBeanRemote;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class Main {

    static final Logger LOGGER = Logger.getLogger(Main.class.getName());

    public static void main(String[] args) {
        try {
            CalculadoraBeanRemote remote = (CalculadoraBeanRemote) new InitialContext()
                .lookup("java:global/CalculadoraEJBModule/CalculadoraBean");
            long base = 10L;
            long num = remote.factorial(base);
            LOGGER.log(Level.INFO, "factorial de {0}={1}", new Object[]{base, num});
        } catch (NamingException ex) {
            LOGGER.log(Level.SEVERE, null, ex);
        }
    }
}


Notar la línea del InitialContext().lookup(), específicamente en su parámetro donde se le indica el nombre del EJB en el servidor. Para resumir la explicación, está compuesta por tres partes:
  • java:global: Es utilizado a partir de la especificación EJB 3.1, donde ya todos los EJB tendrán un mismo nombre JNDI. Antes cada proveedor de EJB daban por su lado y provocaba confusiones y nada de portabilidad entre proveedores
  • CalculadoraEJBModule: Es el nombre del módulo. Como en este caso es un módulo autónomo (no es parte de un Enterprise Application .EAR) se pone su nombre. Pero si fuera parte de un EAR, entonces debería anteponerse el nombre del EAR (sin la extensión .ear)
  • CalculadoraBean: Esto es fácil. Sí, es el nombre del Bean, descrito con @Stateless/@Stateful/@Singleton
Algo más e importante, es necesario agregar un .jar que contenga la interfaz del EJB a este proyecto. En NetBeans bastará con agregar  al proyecto del cliente el proyecto del EJB como biblioteca.

4. Agregar el .jar de GlassFish en el cliente

Este paso es necesario para poder utilizar toda la batería de GlassFish en el cliente. Debería agregarse unicamente el archivo gf-client.jar que se encuentra en el directorio $GLASSFISH_HOME/modules/.

5. Ejecutar el cliente

Y voilá!... la aplicación funcionando.

¿Y si el cliente está en otro computador?
No os preocupéis, que para todos hay.

4a. Configurar un parámetro de ejecución en el cliente indicando la ubicación del servidor

Por omisión el parámetro es "localhost". Pero ¿cuál es el parámetro? Es una propiedad de ejecución llamado org.omg.CORBA.ORBInitialHost Es necesario agregar esto en las propiedades del proyecto cliente.
-Dorg.omg.CORBA.ORBInitialHost=SERVIDOR_EJB


¿Y si configuré mi GlassFish para que usara otro puerto para EJB?
Usar la propiedad org.omg.CORBA.ORBInitialPort en el cliente.
Por omisión es el 3700.


Código fuente

Los proyectos usados para este ejemplo están aquí:

19 comentarios :

Anónimo dijo...

Muy burn tutorial, gracias por la info, quisiera saber como podria hacer lo mismo pero en vez del cliente realizarlo en un pagina jsp, o mejor aun conectar el EJBmodule con un proyecto web en JSF, chau.

Diego Silva dijo...

En el post "¿Para qué los EJB?" (http://www.apuntesdejava.com/2008/08/para-que-los-ejb.html) se explica cómo usar.

También hay un vídeo de cómo hacer una aplicación con JSF 2.0/EJB3.1 en NetBeans 6.8

http://www.apuntesdejava.com/2009/12/netbeans-68-jsf-20-ejb-31-javaee-6.html

pabava dijo...

Me pasa algo curioso con el ejemplo, si selecciono el archivo gf-client.jar desde la carpeta donde esta instalado el glassfish funciona bien, pero si lo copio a otra carpeta y lo selecciono desde otra carpeta me sale este error,

Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial

Inclusive copie todo el contenido de la carpeta modules y lo mismo

Depronto te a pasado y sabes a que se deba esto?

Diego Silva dijo...

Cuando lo agregas por las propiedades del proyecto, lo que hace es agregarlo al "path" de la aplicación. Cuando haces "Build", copiará el .jar en la subcarpeta "lib" de la carpeta "dist" para que sea utilizado por la aplicación. Cuando distribuyas la aplicación, debes llevar todo el contenido de la carpeta "dist", solo así funcionará.

farresbj dijo...

¿Y que pasa si cambia la implementación del EJB en el servidor? Estamos importando todo el proyecto EJB. ¿Hemos de copiar la libreria en todas las carpetas lib de todas nuestras aplicaciones cliente? ¿Hay otra forma más ágil, como los stubs i demás de WebServices que Netbeans crea automáticamente?

Javier Latorre dijo...

Hola, que buena guia, me funciona todo menos cuando pongo el cliente en otro computador... añadi estas lineas pero sigue sin conectar... que pasara??

props.setProperty("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory"); props.setProperty("java.naming.factory.url.pkgs", "com.sun.enterprise.naming"); props.setProperty("java.naming.factory.state", "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl"); props.setProperty("org.omg.CORBA.ORBInitialHost", "192.168.1.2"); props.setProperty("org.omg.CORBA.ORBInitialPort", "3700");
InitialContext ic = new InitialContext(props);
CalculadoraBeanRemote remote = (CalculadoraBeanRemote) ic .lookup("java:global/CalculadoraEJBModule/CalculadoraBean");

Diego Silva dijo...

Hola Javier,
que raro !

pero has intentado la parte de agregar las propiedades en la misma aplicación? O sea, en la línea de comandos (o como está en la parte 4.a) colocando -Dorg.omg.CORBA.ORBInitialHost=192.168.1.2

Algo así sería si se llama desde la línea de comandos:
java -Dorg.omg.CORBA.ORBInitialHost=192.168.1.2 -jar ......

Javier Latorre dijo...

le agregue la linea de comando, sin embargo sigue molestando, estuve ojeando la pagina http://www.java.net/forum/topic/glassfish/glassfish/ejb-client-runs-netbeans-not-outside-0
y no me dieron muchas esperanzas de que funcionara el programa, he desactivado firewalls, actualizado glassfish, monte el proyecto en eclipse y el error es siempre este:

javax.naming.NoInitialContextException: Cannot instantiate class...

Anónimo dijo...

Muchisimas gracias... Lo habia estado buscando, publica mas cosas asi. Que si sirvem

Anónimo dijo...

Se agradece por compartir el conocimiento y la inform y aquí dejo un enlace donde hay un tutorial de un resumen de toda la tecnología java y sus ventajas con ejemplos desarrollados usando el IDE NetBeans ->http://netbeans.org/kb/docs/javaee/ecommerce/netbeans-ecommerce-tutorial.html

Diego Silva dijo...

Gracias Anónimo.
En la misma página de NetBeans hay bastante documentación interesante, además de su Wiki http://wiki.netbeans.org/CommunityDocs_Contributions

ajuarezg dijo...

Exelente ejemplo, me corrio todo, pero un problema cuando trate de correrlo con java web start, saben como hacerlo...sos

Diego Silva dijo...

gracias aJuerzg
Para que se ejecute en JWS, se deberán agregar las bibliotecas del GlassFish... pero ten cuidado porque cuando el cliente quiera acceder desde la web, tendrá que bajar toda esa biblioteca, y puede tomar varios minutos, dependiendo de la velocidad de la red.

Willy Blas dijo...

Hola a todos, sigui los pasos y me corrioen forma local con el netbeans y glassfish el problema es q cuando lo compilo a jar y lo ejecuto java -jar xx.jar me sale el siguiente error

javax.naming.NoInitialContextException: Cannot instantiate class: com.sun.enterprise.naming.SerialInitContextFactory [Root exception is java.lang.ClassNotFoundException: com.sun.enterprise.naming.SerialInitContextFactory]

alguien sabe por q no corre con el jar, estoy q me rompo la cabeza y nada

Willy Blas dijo...

bueno segui los pasos con netbeands 7 y glassfish 3.1 y jdk 1.6 y al ejecutar en el netbeands corria pero cuando lo compilaba me salia error, esto era por agregar las librerias gf-client.jar para solucionar copie los siguientes *.jar de glassfish

auto-depends.jar
bean-validator.jar
common-util.jar
config.jar
config-api.jar
config-types.jar
connectors-internal-api.jar
container-common.jar
deployment-common.jar
dol.jar
ejb.security.jar
ejb-container.jar
gf-client.jar
gf-client-module.jar
glassfish-api.jar
glassfish-corba-asm.jar
glassfish-corba-codegen.jar
glassfish-corba-csiv2-idl.jar
glassfish-corba-newtimer.jar
glassfish-corba-omgapi.jar
glassfish-corba-orb.jar
glassfish-corba-orbgeneric.jar
glassfish-naming.jar
gmbal.jar
hk2-core.jar
internal-api.jar
javax.ejb.jar
javax.jms.jar
javax.resource.jar
javax.servlet.jar
javax.transaction.jar
jta.jar
kernel.jar
management-api.jar
orb-connector.jar
orb-enabler.jar
orb-iiop.jar
security.jar
tiger-types-osgi.jar
transaction-internal-api.jar

pero aun no logro correr remotamente, por alguna razon el programa inicia pero al tratar de crear el objeto se keda buscando el servidor o el puerto, ya me fije y el puerto es el correcto, incluso lo cambie para probar y nada, se queda en esta linea
CalculadoraBeanRemote remote = (CalculadoraBeanRemote) ic .lookup("java:global/CalculadoraEJBModule/CalculadoraBean");
si alguien tiene algubna idea por q no puedo onectar remotamente se lo agradeceria mucho

LOS CRUZETAS F.C dijo...

Hola como puede acceder a mi aplicacion JSF desde otra maquina que este en la misma red....la aplicacion la hice en netbeas....mi idea es algo asi http://direcciondemimaquina:8080/miaplicacion

Diego Silva dijo...

Hola Cruzetas
has revisado que esté habilitado el puerto 8080 en el firewall de la maquina que tienes el JSF?

saludos

trazzo dijo...

Hola,he seguido las instrucciones paso a paso pero en el punto donde "es necesario agregar un .jar que contenga la interfaz del EJB a este proyecto" lo agrego y me sale el siguiente error "no es posible añadir la referencia a si mismo",¿como puedo resolver este problema?"

juses612 dijo...

hola amigos alguien me podría ayudar e seguido los pasos del tutorial y todo bien el problema viene que no esta el jar gf-client en la catpeta modules,no se porque no aparece en la instalacion del glassfish 3.1.2 y trabajo con netbaens 6.9 alguna solucion sera bienvenida.