Tutorial Completo de CORBA en Java: Servidor, Cliente y Mapeo IDL
Implementación de Sistemas Distribuidos con CORBA en Java
En este documento se detalla la estructura y el código necesario para implementar una arquitectura distribuida utilizando CORBA (Common Object Request Broker Architecture) en Java, abarcando tanto la configuración del servidor como la del cliente, además de los conceptos clave de las interfaces generadas.
Arquitectura del Servidor CORBA
El servidor es el encargado de inicializar el ORB, configurar el POA (Portable Object Adapter), instanciar los objetos remotos y publicar sus referencias en el servicio de nombres.
SERVIDOR:
package Servidor;
import java.util.Scanner;
import org.omg.CORBA.ORB;
import org.omg.CosNaming.NameComponent;
import org.omg.CosNaming.NamingContextExt;
import org.omg.CosNaming.NamingContextExtHelper;
import org.omg.PortableServer.POA;
import org.omg.PortableServer.POAHelper;
public static void main(String[] args) {
1 Servidor gestor = new Servidor(args);
2 gestor.publicarEnNS();
3 gestor.start();
}
public class Servidor extends Thread {
DispensadorCorba dispasc;
ORB orb;
static POA rootpoa;
public Servidor(String args[]) throws Exception {
// Inicializamos el ORB
orb = ORB.init(args, null);
try {
// Obtener la referencia al objeto RootPOA y hacemos un narrow de referencia de objeto a referencia POA
rootpoa = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));
// Activamos el gestor de invocaciones del POA
rootpoa.the_POAManager().activate();
}
// Instanciamos un objeto DispensadorCorba
dispasc = new DispensadorCorba(5);
/** DispensadorCorba.java ***/
package servidor;
import interfaz.*;
public class DispensadorCorba extends DispensadorPOA {
Ascensor ascensores[];
int numAscensores;
public DispensadorCorba(int numasc) {
ascensores = new Ascensor[numasc];
/** AscensorCorba.java **/
public class AscensorCorba extends AscensorPOA {
public AscensorCorba(int num) {
puerta = new Puerta();
/** Puerta.java **/
public class Puerta implements Serializable {
public Puerta() {}
public void abrir() {}
public void cerrar() {}
}
}
public int getPiso() {}
synchronized public void ir(int pisodest) {}
private void bajar(int pisodest) {}
private void subir(int pisodest) {}
}
for (int i = 0; i < numAscensores; i++) {
try {
// Instanciamos un objeto AscensorCorba
AscensorCorba ascensor = new AscensorCorba(i);
// Obtenemos la referencia al sirviente
org.omg.CORBA.Object ref = Servidor.rootpoa.servant_to_reference(ascensor);
ascensores[i] = AscensorHelper.narrow(ref);
} catch (Exception e) {}
}
}
public Ascensor getAscensor(int id) {
return ascensores[id];
}
}
}
public void publicarEnNS() {
try {
// Accedemos al NamingService
NamingContextExt root = NamingContextExtHelper.narrow(orb.resolve_initial_references("NameService"));
// Obtenemos la referencia al sirviente
org.omg.CORBA.Object ref = rootpoa.servant_to_reference(dispasc);
NameComponent path[] = root.to_name("dispensador");
// Unimos dentro del NameService al objeto dispasc con el nombre "dispensador"
root.rebind(path, ref);
} catch (Exception e) {}
}
public void run() {
// Nos quedamos a la espera de peticiones
orb.run();
}
}
Arquitectura del Cliente CORBA
El cliente localiza el objeto remoto a través del servicio de nombres y realiza las peticiones invocando los métodos correspondientes.
CLIENTE
package cliente;
import org.omg.CORBA.*;
import interfaz.*;
import org.omg.CosNaming.*;
import java.util.Scanner;
import interfaz.Ascensor;
public static void main(String[] args) {
1 ControlRemoto gestor = new ControlRemoto(args);
2 gestor.controlar();
}
public class ControlRemoto {
Dispensador disp;
Ascensor asc;
public ControlRemoto(String[] args) throws Exception {
ORB orb = ORB.init(args, null);
try {
org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);
String name = "dispensador";
disp = DispensadorHelper.narrow(ncRef.resolve_str(name));
} catch (Exception e) {}
}
public void controlar() throws Exception {
asc = getAscensorControlar();
int opcion = menu();
asc.ir(pisodest);
}
private Ascensor getAscensorControlar() {
System.out.print("Introduce el ascensor a controlar:");
return disp.getAscensor(id);
}
}
Interfaces y Componentes Clave en CORBA
- Prueba: Interface Java que representa el WLSR del objeto remoto. Se utiliza para contener referencias CORBA. Implementa PruebaOperations y extiende la clase Object de CORBA que usa el cliente.
- PruebaHolder: Diseñado para adecuar el paso de parámetros de tipo out e inout, los cuales sólo pueden pasar argumentos por valor.
- PruebaHelper: Contiene métodos estáticos para operaciones de tipo específico. En el servicio de nombrado, cuando se quiere obtener la referencia de un objeto CORBA y se conoce su tipo, se puede hacer casting explícito (narrowing). Narrow() es una especie de casting que adapta referencias a Objetos genéricos a ObjetosPrueba.
- PruebaOperations: Interface Java que contiene las definiciones de los métodos IDL equivalentes en Java. Contiene el mapeo de tipos, operaciones y excepciones.
- PruebaPOA (Skeleton) y PruebaPOATie.java: Implementa PruebaOperations y es la clase que debe extender el sirviente. Es la encargada de adaptar una referencia de un objeto a un sirviente.
- _PruebaStub: Intermediarios del cliente que hacen accesibles los objetos remotos y transforman los métodos indicados en un array de bytes.
Lenguaje IDL
El lenguaje IDL (Interface Definition Language) es neutral y se utiliza para definir objetos CORBA. Las definiciones IDL, mediante un compilador, se pueden transformar al lenguaje de programación que se desee utilizar. Estas transformaciones están altamente especificadas en CORBA, aunque la generación exacta de ficheros depende de cada ORB.
Name Service (Servicio de Nombres)
Al igual que cualquier otro sistema distribuido, y haciendo uso del Servicio de Nombres, CORBA ofrece la posibilidad de buscar referencias a objetos partiendo de nombres formados por caracteres.
- Los nombres pueden tener múltiples componentes, donde cada componente cuenta con un identificador y una llave.
- El nombre se organiza en un grafo de nombrado. Cada nodo es un objeto denominado entorno de nombrado o contexto de nombrado, el cual mantiene una tabla que relaciona objetos y referencias.
Conceptos Fundamentales
- Sirviente: Entidad de un lenguaje de programación que contiene el código que implementa las operaciones de la interfaz IDL.
- Referencia a Objeto CORBA: Identidad de un objeto CORBA que utiliza un cliente para solicitar operaciones.
- Objeto CORBA:
- Entidad virtual con la que nos podemos comunicar mediante un ORB.
- Se materializa o encarna en una implementación (sirviente).
- A la aplicación que contiene uno o varios objetos se le denomina servidor.
- POA (Portable Object Adapter):
- Su labor: Cuando el ORB recibe un mensaje, lo entrega al POA que gestiona el objeto al cual va dirigido (asociando la referencia del objeto con un sirviente).
- El POA debe saber en qué sirviente se encarna cada objeto CORBA para reenviar cada mensaje recibido al esqueleto (skeleton) adecuado.
- Crea la ilusión de objetos CORBA directos para los clientes.
- Para identificar qué sirviente encarna a un objeto CORBA, el POA utiliza una tabla denominada Active Object Map.