Ejecutando un Session Bean en JBoss

Ciclo de Ejecución.

El entender el ciclo de ejecución de un EJB es clave para comprender sus diversos componentes, a continuación se describe este ciclo para un "Session Bean" :

Ciclo de Session EJB
  1. El cliente ya sea un "Servlet/JSP/Applet" o un simple programa Java de terminal, debe encontrar una referencia del EJB que desea llamar, esto se realiza a través de un directorio de nombres (JNDI/LDAP) el cual proporciona una referencia del EJB. Por lo general todo Application Server contiene este tipo de servicio el cual es activado al arranque del mismo, sin embargo, es posible que este servicio de localización sea ofrecido por un producto no incluido con el Application Server.

  2. Se envía el resultado hacia el Cliente indicando la ubicación del denominado EJB, una vez obtenida esta ubicación es posible generar el EJB.

  3. El Cliente invoca el método create del Home Interface del EJB.

  4. Posteriormente el "EJB Container" genera una instancia del EJB que fue llamado por el cliente.

  5. Es necesario asociar la instancia generada con el Remote Interface del EJB , esto permite invocar "métodos/lógica de ejecución" sobre el EJB.

  6. Se retornan los resultados de creación del EJB al Cliente.

  7. Una vez confirmado que la instancia del EJB fue generada, el cliente puede invocar los respectivos métodos sobre el EJB.

  8. A través del Remote Interface del EJB se invocan los respectivos métodos sobre la instancia del EJB.

  9. Ejecutados los métodos sobre la instancia del EJB en cuestión, se retornan los resultados al cliente.

Estructura y Componentes Adicionales.

La estructura básica de EJB's es solo una parte necesaria para la ejecución exitosa de un EJB, a continuación se mencionan otros componentes necesarios para su ejecución.

Stubs y Skeletons

La comunicación ilustrada entre el cliente y el "EJB Container" en la gráfica anterior es llevada acabo mediante procedimientos remotos (via RMI/IIOP), esto implica que el cliente y el "EJB Container" pueden residir en distintos "Hosts" (Computadoras Físicas), y de aquí surge una pregunta clásica de ambientes distribuidos : Como sabe el cliente la definición del EJB ?, Como sabe que métodos llamar ? , la manera en que el cliente se entera de esto es a través de un Stub.

Un Stub proporciona una estructura al cliente que describe los elementos definidos en Servidor, en este caso el EJB. Este Stub es generado por una herramienta proporcionada por el Application Server el cual debe estar accesible al Cliente que intenta comunicarse con el "EJB"/Application Server.El Skeleton es la contra parte del Stub que reside en Servidor, para efectos de EJB's este componente es llevado acabo a través del "Home Interface" y "Remote Interface".

Aunque es importante conocer el uso de Stubs y Skeletons en EJB's, generalmente la comunicación entre el Cliente y EJB es llevada automáticamente y sin mayor preocupación debido a que tanto el "EJB Container" y "Servlet Container" se encuentran en la misma estructura del Application Server y por ende en el mismo ("Host") (Computadora Física). Uno de los casos donde resulta crítico tomar en consideración el uso de Stubs y Skeletons es cuando se posee un ambiente de Cluster, lo cual implica que existe comunicación entre diversos Application Servers en diversos "Hosts" (Computadoras Físicas).

Librerías (JAR's) Propietarias

Además de estos Stubs y Skeletons también existen diversas librerías que son proporcionadas en los diversos Application Servers, estas librerías (Archivos JAR) deben estar accesibles al Cliente o Servidor según lo requiera el Application Server.

Codificación de un Session (Stateless) EJB.

El siguiente EJB es utilizado para obtener el cálculo de Interés sobre cierto monto enviado por un cliente (JSP/Servlet/Applet). Al diseñar un EJB primeramente se diseñan las interfases de éste, a continuación se describen ambas:

Para compilar las Clases de un EJB es necesario tener acceso a la implementación J2EE de las respectivas Clases, en este caso, JBoss proporciona esta librería en la siguiente ubicación :

$JBOSS_HOME/server/default/lib/jboss-j2ee.jar ; donde $JBOSS_HOME es el directorio raíz de instalación de JBoss.

Por lo tanto antes de intentar compilar estas Clases, dicha librería debe ser agregada al CLASSPATH del ambiente Java.

"Remote Interface" Interses.java
package com.osmosislatina.ejb.intereses;

import javax.ejb.EJBObject;
import java.rmi.RemoteException;

public interface Intereses extends EJBObject { 

   public double calcularInteres(double capital, double tasa, double plazo)
       throws RemoteException;

}

Como toda otra interfase en Java, nótese que solo se describen los métodos que serán empleados por el EJB, el único método definido para este EJB es denominado calcularInteres el cual toma 3 parámetros de ejecución; otros detalles notorios de este "Remote Interface" y cualquier otro son:

"Home Interface" IntersesHome.java

El "Home Interface" de un "EJB" define los métodos utilizados para la creación/destrucción del mismo, por lo que pudiera ser considerada una interfase administrativa para el EJB.

package com.osmosislatina.ejb.intereses;

import javax.ejb.EJBHome;
import javax.ejb.CreateException;
import java.rmi.RemoteException;

public interface InteresesHome extends EJBHome { 

   Intereses create() throws RemoteException, CreateException; 

}

Los detalles notorios de este "Home Interface" y cualquier otro son:

"Enterprise Bean Class" IntersesBean.java

Una vez definidas las interfases del EJB es posible implementar el EJB en sí.

package com.osmosislatina.ejb.intereses;

import javax.ejb.SessionBean;
import javax.ejb.SessionContext;

public class InteresesBean implements SessionBean { 
      
   public double calcularInteres(double capital, double tasa, double plazo) { 
   
   System.out.println("Un Cliente llamo la función para calculo de Interés");
   return capital * Math.pow(1+tasa, plazo) - capital;
   }

   public InteresesBean() {}
   public void ejbCreate() {}
   public void ejbRemove() {}
   public void ejbPassivate() {}
   public void ejbActivate() {}
   public void setSessionContext(SessionContext sc) {}
}

Aquí se puede notar que la implementación del EJB utiliza la clase SessionBean, debido a esto es necesario implementar todos aquellos métodos definidos en SessionBean que incluyen:

En este EJB no se define ningún tipo de lógica para estos métodos, sin embargo, en ocasiones se define cierta lógica que debe ser ejecutada al crear,destruir,activar y/o pasivar cualquier EJB, generalmente este caso se presenta en EJB's de Entidad ("Entity EJB's") .

Además de estos métodos, deben implementarse todos aquellos definidos en el "Remote Interface" del EJB, en este caso solo existe calcularInteres donde se define la lógica de negocios a realizarse.

"Deployment Descriptor" ejb-jar.xml

El "Deployment Descriptor" es la última parte a definir en la generación de un EJB.

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE ejb-jar PUBLIC
	"-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN"
	"http://java.sun.com/dtd/ejb-jar_2_0.dtd">

 <ejb-jar>
      <description>Calculo de Intereses</description>
      <display-name>Calculo</display-name>
      <enterprise-beans>
        <session>
          <ejb-name>Calculo</ejb-name>
          <home>com.osmosislatina.ejb.intereses.InteresesHome</home>
          <remote>com.osmosislatina.ejb.intereses.Intereses</remote>
          <ejb-class>com.osmosislatina.ejb.intereses.InteresesBean</ejb-class>
          <session-type>Stateless</session-type>
          <transaction-type>Bean</transaction-type>
        </session>
      </enterprise-beans>
 </ejb-jar>

Se puede notar que son definidos los nombres de cada parte del EJB en conjunción con otros parámetros, de especial importancia es el parámetro ejb-name el cual indicará el nombre asociado con este EJB y que eventualmente será publicado por el "Servidor de Nombres" JNDI/LDAP.

La generación del "Deployment Descriptor" generalmente se lleva acabo a través de alguna herramienta proporcionada con el Application Server, aunque es posible definirlo manualmente, observará que diversos parámetros son un tanto crípticos y por ende se opta por automatizar su creación a través de las herramientas proporcionadas con el Application Server que este utilizando.

Creación del EJB (Archivo JAR) y Ejecución ("Deployment")

Finalmente es necesario agrupar todos los componentes del EJB en un archivo JAR, al igual que el "Deployment Descriptor", la creación de este archivo EJB-JAR generalmente se lleva acabo a través de herramientas proporcionadas con el Application Server y varía según este.

A continuación se describe la creación de éste archivo EJB-JAR mediante el comando jar proporcionado con el JDK, dada la siguiente estructura de directorios/archivos, ejecute el comando jar cvf Intereses.jar * estando en el directorio raíz :

 
  +-com-+
  |     |
  |     +-osmosislatina-+
  |                     | 
  |                     +-ejb-+
  +-META-INF-+                |
             |                +-intereses-+
             |                            | 
             +-ejb-jar.xml                +-Intereses.class
                                          | 
                                          +-InteresesHome.class
                                          |
                                          +-InteresesBean.class

El proceso anterior genera el archivo Intereses.jar, el cual contiene un EJB en estado para ser ejecutado en el "EJB Container".

La ejecución ("Deployment") de un EJB en un Application Server/"EJB Container" varía substancialmente de vendedor a vendedor, en el caso de JBoss solo es necesario colocar el archivo JAR (EJB-JAR) generado anteriormente, bajo el directorio $JBOSS_HOME/server/default/deploy y esto inicializa el EJB, donde $JBOSS_HOME es el directorio raíz de JBoss; sin embargo, vale mencionar que en otros Application Servers como WebLogic o WebSphere pueden utilizarse herramientas especiales para realizar esta tarea de ejecución ("Deployment").

Codificación del Cliente para un Session(Stateless) EJB.

Para interactuar con el Session Bean es necesario crear un cliente, a continuación se diseña un cliente que opera como un programa Java de terminal, este cliente también pudo ser diseñado como un JSP/Servlet o Applet, sin embargo, para otorgar mayor sencillez a su creación se opto por este tipo de cliente.

"Cliente del EJB" ClienteIntereses.java

package com.osmosislatina.ejb.intereses;

import java.util.Properties;
import javax.rmi.PortableRemoteObject; 
import javax.naming.*;

class ClienteIntereses
 {
    public static void main(String[] args)
    {
       Properties env = new Properties();
       
       // Definir las propiededas y ubicación de búsqueda de Nombres JNDI.
       env.setProperty("java.naming.factory.initial",  "org.jnp.interfaces.NamingContextFactory");
       env.setProperty("java.naming.provider.url",  "localhost:1099");
       env.setProperty("java.naming.factory.url.pkgs",  "org.jboss.naming");

       try
       {
          // Traer el Contexto de Nombre 
          InitialContext jndiContext = new InitialContext(env);
          System.out.println("Contexto Disponible");
          
          // Traer la Referencia del EJB
          Object ref  = jndiContext.lookup("Calculo");
          System.out.println("Se encontró Referencia del EJB!");
          
          // Traer la referencia del "Home Interface "
          InteresesHome home = (InteresesHome) 
          PortableRemoteObject.narrow (ref, InteresesHome.class);

          // Crear un Objeto  a partir del "Home Interface"
          Intereses interes = home.create();

          // Llamar la función 
          System.out.println("Interés de 10,000 Capital, a tasa 10%, bajo 2 plazos anuales:");
          System.out.println(interes.calcularInteres(10000, 0.10, 2));
       }
       catch(Exception e)
       {
          System.out.println(e.toString());
       }
    }
 }

  1. La primer sección de este programa define las propiedades del directorio para nombramientos JNDI, en este caso se indica el Directorio de nombres que reside en la maquina local (localhost) utilizando el puerto TCP 1099, este directorio JNDI es ejecutado automáticamente al iniciar JBoss y es el que otorga servicios de nombramiento a los EJB's.

  2. La segunda sección (donde inicia el Bloque try) inicializa el Contexto JNDI con los parámetros definidos anteriormente (env).

  3. Una vez inicializado el Contexto JNDI se realiza una búsqueda para el componente llamado Calculo, este nombre es precisamente aquel designado en el "Deployment Descriptor" del EJB, en otras palabras, se esta realizando una búsqueda por el EJB; si es exitosa la búsqueda se imprime un mensaje.

  4. Posteriormente se trae una referencia del "Home Interface", seguido de la generación del Objeto a través de la función create.

  5. Finalmente se llama la función calcularInteres del Objeto.

Antes de intentar compilar este programa llamado ClienteIntereses.java recuerde que debido al uso de Procedimientos Remotos(RMI/IIOP), se requieren los Stubs correspondientes; en este caso los Stubs corresponden a las interfases InteresesHome.class e Intereses.class, ambas fueron compiladas para el EJB. Esta inclusión anterior significa que deben estar disponibles en el CLASSPATH de Java al compilarse el cliente.

Además de estas Clases, debido a que el "EJB Container" en cuestión es JBoss, se deberán incluir los archivos JAR que son requeridos por Clientes que intentan accesar JBoss, esto es, también deben ser agregados al CLASSPATH de Java, el siguiente comando lo demuestra:

[root@servidor1 jboss]# java -classpath "$CLASSPATH:/usr/local/jboss/
client/jbossall-client.jar com.osmosislatina.ejb.intereses.ClienteIntereses