PRACTICAS
Práctica
1
Práctica
2
Práctica
3
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
|