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í: