Introducción a los Servicios Web en Java

Hoy en d�a, muchas aplicaciones implementan l�gica de negocios de la 'tercera capa' como componentes est�ndar J2EE. Exponer estos componentes como Servicios Web SOAP los hace accesibles casi universalmente -- y proporciona un simple mecanimo para integrar estos componentes. La arquitectura modular J2EE hace que este proceso sea relativamente f�cil.

En esta p�gina veremos c�mo exponer componentes J2EE como Servicios Web y c�mo usar Java Message Service (JMS) para enviar mensajes SOAP de forma eficiente. Principalmente hablaremos sobre Enterprise Java Beans (EJBs), porque son los componentes J2EE m�s ampliamente utilizados para la implemetnaci�n de l�gica de negocios, pero todas las t�cnicas demostradas tambi�n se aplican a otros componentes J2EE, como fuentes de datos JDBC o colas JMS.

.�Procesamiento Est�ndar J2EE

Primero sumarizaremos algunos hechos importantes sobre la plataforma J2EE. Tradicionalmente, la aplicaci�n cliente J2EE usa JNDI para encontrar componentes J2EE en el lado del servidor. Por ejemplo, la aplicaci�n cliente busca la referencia EJB en JNDI y recibe un cliente proxy EJB, que luego el cliente puede usar para acceder al cliente EJB. Toda la comunicaci�n J2EE normalmente ocurre sobre RMI.

.�J2EE -- Aproximaciones B�sicas

Hay dos aproximaciones b�sicas para acceder a recursos J2EE mediante SOAP.

Empezaremos con la aproximaci�n m�s �biva, que es crear una Servicio Web envoltura alrededor del EJB. Esta aproximaci�n es apropiada particularmente en situaciones donde la aplicaci�n del Servicio Web no se mapea directamente a las capacidades de un EJB individual y requiere alguna orquestaci�n adicional de componentes J2EE.

En nuestro segundo ejemplo prosentaremos una aproximaci�n de integraci�n transparente con menos c�digo. Su objetivo principal es exponer aplicaciones J2EE existentes como Servicios Web tan r�pida y din�micamente como sea posible. Esta aproximaci�n nos permitir� acceder efectivamente a aplicaciones J2EE existentes sobre SOAP sin escribir o modificar ning�n c�digo.

.�El ejemplo "Stock Quote EJB Wrapper"

En este ejemplo presentaremos la aproximaci�n del Servicio Web envoltura alrededor de un EJB para acceder a un simple bean de sesi�n sin estado. Esta aproximaci�n de envoltura es muy simple, y se utiliza ampliamente en muchos marcos de trabajo SOAP. S�lo hay ligeras diferencias entre las distintas implementaciones, que generalmente pertenecen al nivel de autom�tizaci�n del proceso de desarrollo. Esta aproximaci�n requiere el despliegue de un Servicio Web que envuelva uno o m�s componentes J2EE existentes. Esta envoltura act�a como un puente entre el mundo SOAP y el mundo RMI. Los clientes env�an solicitudes SOAP a la envoltura, y la envoltura las traduce en solicitudes RMI al componente EJB. Esta aproximaci�n se recomienda para usarla con recursos J2EE sin estado, como beans de sesi�n sin estado. Para acceder a recursos con estado usando esta t�cnica necesitar�amos configurar servicios de ciclo de vida adiconales para manejar la eliminaci�n apropiada de los recursos con estado hu�rfanos.

Primero necesitamos realizar algunos pasos de instalaci�n y configuraci�n muy sencillos:

  1. Instalar el servidor WASP.
  2. Descargar el c�digo fuente y descomprimirlo en el directorio c:\wasp_demo.
  3. Usar la implementaci�n de referencia de J2EE 1.3 que puedes descargar desde la website de Sun.
  4. Despu�s de instalar el J2EE, tenemos que configurar el entorno de ejecuci�n de WASP para que lo utilice haciendo un par de cambios en el script env.bat localizado en el subdirectorio bin en el directorio de instalaci�n de WASP.
    • Primero comenta la siguiente l�nea (poniendo rem al principio de la l�nea:
      set INSTALLATION_TYPE=standalone
    • Luego quita el comentario de la siguiente l�nea del mismo fichero:
      set INSTALLATION_TYPE=j2ee
  5. Tambi�n necesitamos modificar el script env.bat localizado en el directorio c:\wasp_demo\bin. Por favor, localiza los valores correctos para las variables de entorno J2EE_HOME, WASP_HOME y WASP_DEMO.

Una vez completados los pasos de instalaci�n y configuraci�n de arriba, arrancamos el servidor J2EE y el entorno de ejecuci�n WASP usando los scripts startJ2EE y startserver. Luego ejecutamos el script deploy_j2ee para compilar el c�digo fuente Java y desplegar los EJB que usaremos en estos ejemplos.

NOTA:
Necesitar�s reiniciar el servidor J2EE despu�s de desplegar los EJBs.

Puedes ver el c�digo fuente Java en el paquete com.systinet.demos.stock para ver que las clases StockQuote, StockQuoteHome y StockQuoteBean implementan un bean de sesi�n sin estado bastante sencillo con un s�lo m�todo getQuote. Ya hemos desplegado este EJB al llamar al script deploy. Podemos asegurarnos que todos los EJBs se han desplegado correctamente usando la herramienta de administraci�n de J2EE. Ejecuta el script J2EEAdmin desde el directorio bin del ejemplo para arrancar la herramienta de administraci�n.

Ahora nos concentraremos en la implementaci�n del Servicio Web Envoltura, listado abajo. Implementa un m�todo getQuote, que contiene una simple invocaci�n EJB. Primero recupera la referencia home del EJB desde JNDI y crea un ejemplar EJB. Luego invoca el m�todo getQuote del EJB, y elimina el EJB. Finalmente se devuelve el resultado de la invocaci�n al cliente del Servicio Web. Podemos ver estos pasos en el c�digo de abajo:

package com.systinet.demos.stock;

import javax.naming.InitialContext;
import javax.naming.Context;
import javax.naming.NamingException;
import java.rmi.RemoteException;


public class StockQuoteService {
	
    public double getQuote(String symbol) throws Exception {
        
        // get the JNDI initial context
        System.err.println("Getting J2EE initial context");
        Context jndiContext = new InitialContext();
        // lookup the EJB home
        System.err.println("Looking up EJB Home");
        Object homeRef = jndiContext.lookup("Stock");
        StockQuoteHome home = 
        (StockQuoteHome)javax.rmi.PortableRemoteObject.narrow(
        homeRef, StockQuoteHome.class);
        // create the EJB instance
        System.err.println("Creating EJB");
        StockQuote ejb = home.create();
        // call the getQuote method
        System.err.println("Calling getQuote");
        double quote = ejb.getQuote("SUNW");
        System.err.println("SUNW "+quote);
        // remove the EJB
        System.err.println("Removing EJB");
        ejb.remove();
        return quote;
    }
}

Ahora podemos desplegar el Servicio Web ejecutando el script deploy_service. Luego ejecutamos el script run_wrapper para arrancar el cliente del Servicio Web que invoca al Servicio Web.

NOTA:
Hemos hecho este ejemplo tan sencillo para ilustrar los principipos b�sicos de la aproximaci�n envoltura; sin embargo, las aplicaciones del mundo real normalmente son un poco m�s complejas. Un servicio envoltura normalmente se usa para ensamblar funcionalidades de varios EJBs y otros recursos J2EE. En dichos casos, el servicio envoltura normalmente expone diferentes interfaces program�ticos de los beans originales.

.�Integraci�n J2EE Transparente

Otra forma de acceder a recursos J2EE es usar el marco de integraci�n transparente. Con 'transparente' queremos decir que no es necesario escribir un servicio envoltura o modificar el c�digo J2EE original. Esta aproximaci�n es m�s �til si tenemos recursos J2EE existentes que queremos hacer disponibles para clientes SOAP o si tenemos clientes J2EE que necesitan acceder a recursos J2EE a trav�s de Internet.

El marco de integraci�n transparente J2EE descrito abajo explita las fortalezas de la arquitectura JNDI, que proporciona un mecanismo abstracto para acceder a recursos J2EE. Como dijimos anteriormente, en el procesamiento normal J2EE, un cliente J2EE llama el m�todo lookup de JNDI, y el proveedor JNDI del ciente le pasa esta solicitud mediante RMI a otro servicio JNDI dentro del servidor J2EE. JNDI devuelve un proxy J2EE al cliente, que �ste utiliza para invocar a los m�todos del recurso J2EE remoto sobre RMI. En este ejemplo, usaremos un proveedor JNDI en el lado del cliente que habla SOAP en vez de RMI. Como puedes ver en la siguiente figura, cuando el cliente env�a una llamada JNDI usando este proveedor, la solicitud se env�a sobre SOAP a un Servicio Web JNDI. Este Servicio Web JNDI realiza la b�squeda real en el servidor de aplicaciones JNDI, obteniendo el proxy J2EE. Entonces el Servicio Web JNDI devuelve una del proxy J2EE. Despu�s la aplicaci�n cliente puede usar estas referencia remota para invocar los m�todos del recurso J2EE. Cada invocaci�n de m�todo se transporta sobre SOAP al proxy J2EE, que redirige la solicitud al recurso J2EE real. Observar�s que no se requieren modificaciones de c�digo ni en el recurso J2EE ni en el cliente. S�lo se requieren unos cambios de configuraci�n en el cliente para que apunte al proveedor JNDI basado en SOAP.

NOTA:
La mayor�a de los servidores de ejecuci�n de Servicios Web operan en el mismo contexto que el servidor de aplicacion, por eso la invocaci�n redirigida es muy r�pida y no degrada el rendimiento.

Esta aproximaci�n tambi�n funciona para clientes no-Java. Ya que el Servicio Web JNDI es un Servicio Web est�ndar, cualquier cliente SOAP se puede aprovechar de este marco de invocaci�n transparente. Por ejemplo, un cliente Microsoft Visual Basic puede llamar al m�todo lookup del Servicio Web JNDI y obtener el proxy Servicio Web del recurso J2EE solicitado.

El Servicio Web JNDI realiza recolecci�n de basura autom�tica de todos los componentes creados en el entorno de ejecuci�n de Servicios Web. La mayor�a de esos componentes se descartan bajo demanda cuando una aplicaci�n cliente descarta expl�citamente el componente remoto, pero no hay garant�a de la eliminaci�n correcta en el mundo de los Servicio Web de acoplamiento ligero. Esto es por lo que a los recursos creados din�micamente les sigue la pista y los maneja el servicio LifeCycle.

La mayor ventaja de esta aproximaci�n es que proporciona acceso SOAP inmediato y transparente a cualquier recurso J2EE registrado en JNDI, incluyendo todo tipo de componentes EJB (beans de sesi�n con o sin estado, beans de entidad, y beans dirigidos por mensaje), adem�s de JMS, JDBC y otros recursos J2EE. No se necesitan modificaciones ni envolturas para los recursos J2EE. Esta aproximaci�n obviamente es muy �til para proporcionar un acceso r�pido y f�cil a sistemas existentes mediante SOAP. Veamos un ejemplo.

.�Ejemplo de Integraci�n Transparente J2EE

Este ejemplo usa un Servicio Web llamando a un EJB que se est� ejecutando en el motor de la implementaci�n de referencia de Sun (J2EE 1.3).

Primero chequeemos el c�digo del EJB del lado del servidor. Como puedes ver, es un bean de sesi�n con estado est�ndar que mantiene el estado de un simple contador:

package com.systinet.demos.counter;

import javax.ejb.CreateException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.ejb.SessionSynchronization;

public class CounterEJB implements SessionBean {
    
    private SessionContext context;
    
    private int count = 0;

    /**
     * No argument constructor required by container.
     */
    public CounterEJB() {
    }

    /**
     * Create method specified in EJB 1.1 section 6.10.3
     */
    public void ejbCreate() {
    }

    /* Methods required by SessionBean Interface. EJB 1.1 section 6.5.1. */

    /**
     * @see javax.ejb.SessionBean#setContext(javax.ejb.SessionContext)
     */
    public void setSessionContext(SessionContext context){
        this.context = context;
    }

    /**
     * @see javax.ejb.SessionBean#ejbActivate()
     */
    public void ejbActivate() {
    }

    /**
     * @see javax.ejb.SessionBean#ejbPassivate()
     */
    public void ejbPassivate() {
    }

    /**
     * @see javax.ejb.SessionBean#ejbRemove()
     */
    public void ejbRemove() {
    }
    
    public long getCount() {
        return count++;
    }
}

Los otros recursos EJB son bastante obvios. Podemos ver el c�digo del Counter remoto y los interfaces home CounterHome. Ya hemos desplegado el EJB en el primer ejemplo invocando el script deploy_j2ee. Por favor, observa que no necesitamos desplegar ning�n Servicio Web espec�fico en el entorno de ejecuci�n de Servicios Web.

La aplicaci�n cliente es un cliente est�ndard EJB con la excepci�n de que usa propiedades JNDI diferentes en el m�todo getInitialContext.

package com.systinet.demos.counter;

import javax.naming.InitialContext;
import javax.naming.Context;
import javax.naming.NamingException;
import java.rmi.RemoteException;

public class CounterClient {

    public CounterClient() {
    }

   public static void main(String [] args){
        try {
            
           // get the JNDI initial context
           System.err.println("Getting J2EE initial context");	
           Context jndiContext = getInitialContext();
           // lookup the EJB home
           System.err.println("Looking up EJB Home");
           Object homeRef = jndiContext.lookup("Counter");
           CounterHome home = 
              (CounterHome)javax.rmi.PortableRemoteObject.narrow(homeRef, CounterHome.class);
           // create the EJB instance
           System.err.println("Creating EJB");
           Counter ejb = home.create();
           System.out.println("Calling count "+ejb.getCount());
           System.out.println("Calling count "+ejb.getCount());
           System.out.println("Calling count "+ejb.getCount());
           // remove the EJB
           System.err.println("Removing EJB");
           ejb.remove();
        
        } 
        catch(java.rmi.RemoteException re) {
            re.printStackTrace();
        }
        catch(Throwable t) {
            t.printStackTrace();
        }
    }
  
    static public Context getInitialContext() throws javax.naming.NamingException {
        
        java.util.Properties jndiProperties = new java.util.Properties();
        
        jndiProperties.put("java.naming.factory.initial","com.idoox.jndi.InitialContextFactoryImpl");
        jndiProperties.put("java.naming.provider.url","http://localhost:6060");
        
        return new InitialContext(jndiProperties);
    }
}

Por favor, observa que para mentener la simplicidad hemos codificado en el c�digo todos los par�metros espec�ficos JNDI. Hay dos par�metros que necesitamos definir para poder redigir la consolta JNDI al Servicio Web JNDI: java.naming.factory.initial y java.naming.provider.url. Estos parametros normalmente se utilizan en el fichero .properties de la aplicaci�n en vez de estar codificados en la aplicaci�n cliente. En dicho caso, no ser�a necesar�a la recompilaci�n del c�digo.

El siguiente paso es compilar y ejecutar la aplicaci�n cliente J2EE usando el script run. Deber�as ver que se ha llamado al m�todo getCount del EJB tres veces. Toda la comunicaci�n entre la aplicaci�n cliente y el lado del servidor se hace a trav�s de mensajes SOAP. Tambi�n podemos ver que el estado (el valor del contador) se mantiene correctamente.

.�Enviar Mensajes SOAP de Forma Eficiente sobre JMS

Hoy en d�a la mayor�a de los Servicios Web usan el protocolo de transporte HTTP para sus comunicaciones. HTTP es muy adecuado para muchas aplicaciones. Su principal ventaja es la flexibilidad de integraci�n de aplicaciones a trav�s de proxys y firewalls HTTP. Pero para algunas aplicaciones, HTTP podr�a no ser suficiente. HTTP es unidireccional y bloquea mucha de las caracter�sticas t�picas empresariales como, la eficiencia, la persistencia y las transaciones. Su soporte de escenarios de enrutado de mensajes as�ncronos tampoco es ideal. Una aproximaci�n para corregir estos problemas es usar JMS para transportar mensajes SOAP. JMS puede proporcionar beneficios sustanciales para la comunicaci�n de aplicaciones empresariales ya que soporta entrega de mensajes garantizada, colado y 'des-colado' de mensajes transacioanles, y sem�ntica de mensajes s�ncronos y as�ncronos. JMS tambi�n ofrece mucho mejor rendimiento y escalibilidad que el protocolo HTTP.

Este �ltimo ejemplo demuestra que SOAP es realmente independiente del protocolo de transporte. Accederemos al mismo Servicio Web que desarrollamos en el primer ejemplo, pero esta vez enviaremos los mensajes SOAP mediante JMS. La implementaci�n es muy simple, s�lo tenemos que cambiar la url de b�squeda pasada al m�todo lookup al lado del cliente:

package com.systinet.demos.jms;

import org.idoox.wasp.Context;
import org.idoox.webservice.client.WebServiceLookup;

public final class StockClient {

  /**
   * @param args  not used.
   */
    public static void main( String[] args ) throws Exception {
      
      System.setProperty("java.naming.factory.initial","com.idoox.jndi.InitialContextFactoryImpl");  
      System.setProperty("java.naming.provider.url","http://localhost:6060");
      System.setProperty("idoox.demo.transport.j2ee", "true");
        
      // lookup service
      WebServiceLookup lookup = (WebServiceLookup)Context.getInstance(Context.WEBSERVICE_LOOKUP);
      // bind to StockQuoteService
      StockQuoteServiceProxy quoteService = (StockQuoteServiceProxy)lookup.lookup(
"jms://jms/Queue@jms/QueueConnectionFactory~/StockEJBService/",StockQuoteServiceProxy.class);
      

      // use StockQuoteService
         
      System.out.println("Getting SUNW quote");
      System.out.println("------------------------");
      System.out.println("SUNW "+quoteService.getQuote("SUNW"));
      System.out.println("");
    }
}

Compilaremos y ejecutaremos el cliente del ejemplo JMS ejecutando el script run_jms. El marco de trabajo SOAP proporciona un mapeo completamente transparente del protocolo de transporte subyacente, por eso todas las caracter�sticas que mencionamos anteriormente (Servicios Web con estado, referencias remotas, fallos SOAP, etc.) funcionar�n sobre JMS sin modificar nada en el c�digo Java.

NOTA:
El entorno de ejecuci�n de Servicios Web est� pre-configurado para escuchar mensajes SOAP en la cola JMS jms/Queue.

.�Limpieza

Ahora que hemos completado nuestros ejemplo, usamos los scripts undeploy_j2ee y undeploy_service para eliminar los EJB del servidor de aplicaciones y el Servicio Web del entorno de ejecuci�n de Servicios Web.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP
ARTÍCULO ANTERIOR

SIGUIENTE ARTÍCULO