martes, 4 de mayo de 2010

Cliente remoto de EJB 3.1 (en GlassFish V3)

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:

  1. 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.

    ResponderEliminar
  2. 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

    ResponderEliminar
  3. 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?

    ResponderEliminar
  4. 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á.

    ResponderEliminar
  5. ¿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?

    ResponderEliminar
  6. 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");

    ResponderEliminar
  7. 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 ......

    ResponderEliminar
  8. 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...

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

    ResponderEliminar
  10. 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

    ResponderEliminar
  11. 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

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

    ResponderEliminar
  13. 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.

    ResponderEliminar
  14. 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

    ResponderEliminar
  15. 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

    ResponderEliminar
  16. 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

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

      saludos

      Eliminar
  17. 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?"

    ResponderEliminar
  18. 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.

    ResponderEliminar

Si quieres hacer una pregunta más específica, hazla en los foros que tenemos habilitados en Google Groups


Ah! solo se permiten comentarios de usuarios registrados. Si tienes OpenID, bienvenido! Puedes obtener su OpenID, aquí: http://openid.net/