LSID
Universidad de Almería
Laboratorio de
Sistemas de Información Distribuidos

 


PRACTICAS

Práctica 1
Práctica 2
Práctica 3
 

Valid HTML 4.01 Transitional

 
 
 
 
 
 
 
 
 
 

ooooooooooooooo



Práctica 3: Productor/Consumidor CORBA bajo Web

 
MODULO 4: Programación CORBA
 
Para elaborar un sistema de información distribuido, se suele hacer uso de un middleware ORB para conectar las partes software ubicadas en diferentes máquinas, en lugares geográficos diferentes y (en algunos casos) elaborados por diferentes organizaciones. El ORB más clásico y heterogéneo es CORBA, el modelo de componentes distrubuidos de OMG. Como hemos visto en clases de teoría, en el mercado existe una gran diversidad de implementaciones del modelo CORBA, como por ejemplo, Orbacus, TAO, Orbix, etc.

Dada la limitación temporal que disponemos, y dado que aun quedan algunos módulos por desarrollar hasta llegar a tener la aplicación Productor-Consumidor que estamos elaborando, en esta sesión utilizaremos mejor el ORB que lleva implementado la máquina virtual de Java (instalado en el ordenador en las sesiones anteriores).

Para utilizar el ORB de Sun debemos conocer algunos detalles, tanto de la propia implementación de Java como del propio CORBA. En los siguientes apartados construiremos dos simples ejemplos de objeto CORBA para entender su funcionamiento (cómo se usa CORBA). Luego, en relación a lo que hemos aprendido con ese ejemplo, construiremos nuestro objeto CORBA (el buffer) como parte del ejemplo que estamos elaborando: el Productor - Consumidor.

En el módulo siguiente pondremos todo en marcha, uniendo los conceptos de servlet, XML y CORBA adquiridos en cada uno de los módulos.



Ejercicio 1

Como primer ejercicio, vamos a intentar ejecutar el típico ejemplo cliente/servidor de "Hello World!". Para ello, usaremos el tutorial Java IDL de Sun para aprender los primeros pasos con CORBA. Acceda a la página http://java.sun.com para obtener información básica para iniciarnos en CORBA. Localice la versión java que tenga instalado en su ordenador (en el momento de escribir estos apuntes, la versión usada era J2SDK 1.4.2).

Pasos:

  • Visite la página de documentación de java: http://java.sun.com/j2se/1.4.2/docs/
  • En esta página, en la figura que aparece seleccione el bloque CORBA.
  • La página que se muestra es una introducción muy básica sobre CORBA, útil para principiantes en la materia. En la página se describe algunos conceptos de comunicación de RMI, que se usa para hacer comunicaciones entre objetos puramente en java. En la página también se describe cómo compatibilizar RMI y IIOP, este último es el protocolo de CORBA. Por último, casi al final de la página aparece un apartado sobre cómo programar con el IDL de Java. Seleccione el tutorial de iniciación "Tutorial: Getting Started with Java IDL".
  • En la página del tutorial (seleccionado en el paso anterior) se describe cómo poner en marcha el ejemplo más simple: un Hello World!. Realice el ejercicio.
IMPORTANTE: Para poner en marcha objetos CORBA en FEDORA, compruebe antes que existe un nombre de máquina en el /etc/hosts. En caso de no existir, edite el archivo e incluya la IP y el alias asignado para su equipo. Estos aparecen en la pegatina que hay en la parte frontal de cada ordenador (en el laboratorio de prácticas).
   



Ejercicio 2

Agradecimientos a:  CAMACHO MATINEZ, JOSE ALBERTO  y a  PEREZ RIDAO, PEDRO JESUS

Vamos a poner en marcha una primera versión del Buffer de la práctica del Productor  - Consumidor.

El IDL del ejemplo es el siguiente (llamar por ejemplo al archivo Buffer.idl):


module BufferApp {

  interface Buffer {

    boolean put(in string elemento);
    boolean get(out string elemento);

    boolean read(out string elemento);

    oneway void shutdown();

  };

};


Compilamos el archivo IDL de la siguiente forma:


idlj -fall -oldImplBase Buffer.idl


La opción -oldImplBase se usa si el servidor no va ser programado con la extensión POA. La opción -fall crea código CORBA tanto para el lado cliente como para el lado servidor. La compilación crea un directorio con el mismo nombre que el módulo, en este caso un directorio llamado BufferApp (véase IDL de arriba). Acceda, si lo desea, al directorio y vea el contenido de alguno de los archivos. Estos archivos son generados automáticamente por el compilador idlj y se corresponden con la capa de transporte del ORB. No modifique el contenido de estos archivos.

Creamos el Servidor y un Cliente para el buffer. Observe y analice el contenido de estos archivos. Observe en la implementación del Servidor que la pila se ha limitado a 10 elementos, controlando los métodos que no se pasa estos limites. La funcionalidad de la interfaz definida en el paso anterior, se ha implementado directamente en el Servidor, aunque es recomendable hacerlo en un archivo independiente para independizar el código CORBA del código de la funcionalidad. En el ejemplo de abajo (Servidor), la funcionalidad se implementa en la clase BufferImpl. Se puede crear un archivo BufferImpl.java con este código, en lugar de tenerlo todo junto.

// BufferServer.java
import BufferApp.*;

import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;

/**
 * La capa servidor que controla al componente Buffer
 */
public class BufferServer {

  public static void main(String args[]) {
    try {
   
      ORB orb = ORB.init(args, null);
// Crea e inicializa el ORB

     // Crea un hilo (servant) y lo registra en el ORB
      BufferImpl bufferRef = new BufferImpl();
      orb.connect(bufferRef);

      // Obtiene una referencia del objeto
      org.omg.CORBA.Object objRef =
                orb.resolve_initial_references("NameService");

      NamingContext ncRef = NamingContextHelper.narrow(objRef);

      // Activa la referencia
      NameComponent nc = new NameComponent("Buffer", "");
      NameComponent path[] = {nc};
      ncRef.rebind(path, bufferRef);

      System.out.println("Servidor Buffer preparado y esperando ...");

     // Espera indefinidamente atendiendo las peticiones de los clientes
      java.lang.Object sync = new java.lang.Object();
      synchronized(sync){
        sync.wait();
      }
    } catch(Exception e) {
        System.err.println("ERROR: " + e);
        e.printStackTrace(System.out);
      }
  }
}


/**
 * Agregando funcionalidad al componente Buffer
 */
class BufferImpl extends _BufferImplBase {
  private ORB orb;
  private String buf[];
  private int elementos;
  private static int maxElementos = 10;

  // implementa el metodo constructor
  BufferImpl (){

      buf = new String[maxElementos];
      elementos = 0;
  }
 
 // implementa el metodo put()
  public boolean put (String elemento){
    if(elementos<maxElementos) {
       buf[elementos]=elemento;
       elementos++;
       System.out.println(buf[elementos-1]+"\tElementos: "+elementos);
       return true;
    } else {
         elemento="PILA LLENA";
         System.out.println("PILA LLENA");
         return false;
      }

  }

  // implementa el metodo get()
  public boolean get (org.omg.CORBA.StringHolder elemento){
    int i;
    if(elementos>4) {
       elemento.value=buf[0];
       for(i=0;i<maxElementos-1;i++)
         buf[i]=buf[i+1];
       elementos--;
       return true;
    } else { elemento.value="SOLO INTRODUCIR O LEER"; return false;}
  }

 // implementa el metodo read()
  public boolean read (org.omg.CORBA.StringHolder elemento){
    if(elementos!=0) {   
        elemento.value=buf[0];
        return true;
    } else return false;
  }

  // implementa el metodo shutdown()
  public void shutdown() {
    orb.shutdown(false);
  }
}
Tabla. Clase servidor BufferServer.java


Observe tambien en el código cómo el servidor permacene en ejecución de forma indefinida mediante la orden:

synchronized(sync) {
        sync.wait();
}

Veamos ahora el código del cliente.

 //BufferClient.java

 import BufferApp.*;
 import org.omg.CosNaming.*;
 import org.omg.CosNaming.NamingContextPackage.*;
 import org.omg.CORBA.*;

 public class BufferClient {

  static Buffer bufferImpl;


  public static void main(String args[])
    {
      try{

        ORB orb = ORB.init(args, null);

       org.omg.CORBA.Object objRef =
        orb.resolve_initial_references("NameService");
        NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);

        String name = "Buffer";
        bufferImpl = BufferHelper.narrow(ncRef.resolve_str(name));

        StringHolder elem=new StringHolder();

        System.out.println("Referencia:" + bufferImpl);
        System.out.println(bufferImpl.put("Elemento 1"));
        System.out.println(bufferImpl.put("Elemento 2"));
        System.out.println(bufferImpl.put("Elemento 3"));
        System.out.println(bufferImpl.put("Elemento 4"));
        System.out.println(bufferImpl.put("Elemento 5"));
        System.out.println(bufferImpl.put("Elemento 6"));
        //System.out.println(bufferImpl.read(elem)+"\t"+elem.value);
        System.out.println(bufferImpl.get(elem)+"\t"+elem.value);
        System.out.println(bufferImpl.read(elem)+"\t"+elem.value);
        System.out.println(bufferImpl.get(elem)+"\t"+elem.value);
        System.out.println(bufferImpl.read(elem)+"\t"+elem.value);

        bufferImpl.shutdown();

    } catch (Exception e) {
          System.out.println("ERROR : " + e) ;
      e.printStackTrace(System.out);
      }
    }
  }
Tabla. Clase cliente BufferClient.java


Compilamos el cliente y el servidor:

javac *.java BufferApp/*.java

Lanzamos el orb:

orbd -ORBInitialPort 1050 &

Nota 1: El simbolo & al final de una orden lanza un proceso en segundo plano.
Nota 2: Para ejecutar el orbd compruebe que tiene el nombre de la máquina declarado en /etc/hosts.


Lanzamos el servidor:

java BufferServer -ORBInitialPort 1050 

Y en otra ventana lanzamos el cliente:

java BufferClient -ORBInitialPort 1050 

El cliente inserta en el buffer 6 cadenas de caracteres, y luego realiza dos veces las operaciones seguidas de get y read.

Por favor, para mas información consulte la página oficial de Java IDL de SUN.

http://java.sun.com/j2se/1.4.2/docs/



Ejercicio 3

Elabore el servidor CORBA para el productor-consumidor. Para ello, tenga presentes las restricciones que debe cumplir el objeto CORBA, impuestas anteriormente en el Módulo 1 de este manual, en el apartado "Requisitos del objeto Buffer". El cliente servlet podrá tomar dos roles, uno de productor y otro de consumidor:

  • Productor. En este caso, la servlet aceptará dos valores, el e-mail y el elemento. El proceso que sigue internamente la servlet para este rol es que genera un mensaje XML y lo envia al servidor CORBA realizando una llamada el método put(mensaje).
  • Consumidor. En este caso la servlet deberá determinar si el cliente quiere extraer un elemento del buffer o solo consultar el ultimo elemento. Esto se hace internamente llamando desde la servlet a los métodos del servidor get(mensaje) o read(mensaje). En este caso mensaje es el ultimo elemento del buffer que representa un texto XML que encapsulta los dos datos que hay que devolver al cliente: el email y el elemento. Por tanto, para el caso del rol Consumidor es necesario una funcion que realice las tareas de desempaquetamiento del texto XML.



LSID, Laboratorio de Sistemas de Información Distribuidos
  Departamento de Informática
  Universidad de Almeria, España
  Luis.Iribarne@ual.es