Ramón Millán - Consultoría en Tecnologías de la Información y Comunicaciones


Programación de objetos distribuidos con CORBA

Autor: Ramón Jesús Millán Tejedor

Publicado en Programación Actual nº 28, Prensa Técnica S.A., 1999

Introducción

Una característica importante de las grandes redes de ordenadores actuales, como Internet, es su heterogeneidad. La heterogeneidad y la estandarización nos permiten, idealmente, utilizar la mejor combinación de hardware y software, aumentando el rendimiento de las aplicaciones sin afectar a su interoperabilidad, consiguiendo un sistema coherente, eficiente y altamente operativo. Pero la práctica demuestra que cumplir los requerimientos de seguridad, eficiencia, flexibilidad y extensibilidad en sistemas distribuidos heterogéneos es raramente fácil.

Estas exigencias motivaron el uso de CORBA (Common Object Request Broker Architecture). CORBA es un estándar abierto del OMG (Object Management Group) para la programación de aplicaciones distribuidas. CORBA mejora la flexibilidad y portabilidad de las aplicaciones y permite al programador desentenderse de las tareas más complejas que conllevan los entornos distribuidos heterogéneos, con muy diversas máquinas, sistemas operativos y protocolos de comunicaciones. CORBA constituye el soporte fundamental para la consecución de la universalidad de las aplicaciones y es un entorno cada vez más demandado por las empresas dedicadas a las telecomunicaciones avanzadas.

OMG

El OMG es un consorcio internacional sin ánimo de lucro establecido en 1989. Su objetivo es ayudar a reducir la complejidad, disminuir los costes y acelerar la introducción de nuevas aplicaciones software, promoviendo la teoría y la práctica de la tecnología de objetos en los sistemas distribuidos.

Originalmente estaba formada por 13 compañías, pero los miembros del OMG han crecido progresivamente y en la actualidad es el consorcio de software más grande del mundo, compuesto por más de 760 vendedores, programadores y usuarios. De hecho todas las grandes compañías de software interesadas en el desarrollo orientado a objetos distribuidos son miembros del OMG.

El OMG alcanza sus objetivos promoviendo la adopción de especificaciones de interfaz y de protocolo, que permiten la interoperabilidad y portabilidad de las aplicaciones orientadas a objetos distribuidos. En este consorcio no se producen guías de cómo implementar o producir software, sólo especificaciones.

Los miembros del OMG contribuyen tecnológicamente y con ideas en respuesta a RFI (Request For Information) y RFP (Request For Proposals), emitidas por el OMG. El OMG no establece estándares en la industria, se formó para promover mediante el consenso de sus participantes, la adopción de estándares de facto por parte de los vendedores. El estándar a ser adoptado debe existir como una implementación; es decir, sólo se aprueba un estándar si alguien lo ha implementado y se comprueba su correcto funcionamiento.

En su Web Site, https://www.omg.org, se puede encontrar información detallada sobre sus actividades, estándares y la tecnología CORBA en general.

OMA

OMA (Object Management Architecture) o arquitectura de gestión de objetos es el centro de toda la actividad emprendida en el OMG. Se trata de una visión a alto nivel de un entorno distribuido completo y se compone de un modelo de objeto y un modelo de referencia.

En el modelo de objeto de OMA, un objeto es una entidad encapsulada con una identidad inmutable y distinguible, cuyos servicios pueden ser accedidos a través de interfaces bien definidas.

Modelo de referencia de OMA
Figura 1: Modelo de referencia de OMA.

En la Figura 1 se muestran los componentes del modelo de referencia de OMA, encargado de caracterizar las interacciones entre objetos. El componente fundamental es el denominado ORB (Object Request Broker). El ORB es, principalmente, el responsable de facilitar la comunicación entre clientes y objetos. Puede verse como el microkernel de un sistema distribuido. Utilizando el componente ORB hay cuatro categorías de interfaces de objetos, descritas a continuación:

CORBA

Revisión de CORBA

La especificación CORBA detalla las interfaces y características del componente ORB de la OMA. La última actualización hasta el momento es CORBA 2.2. En la Figura 2 se muestra la arquitectura CORBA y cómo se relacionan sus distintos componentes.

Arquitectura de CORBA
Figura 2: Arquitectura de CORBA.

La arquitectura CORBA está orientada a objetos. Los objetos CORBA presentan muchas características de otros sistemas orientados a objetos, incluyendo la herencia de interfaces y el polimorfismo. Lo que hace a CORBA más interesante es que proporciona estas capacidades, incluso cuando es utilizado en lenguajes no orientados a objeto como C o COBOL, aunque CORBA trabaja particularmente bien con lenguajes orientados a objeto como C++ y Java.

Dentro de las nuevas técnicas y lenguajes de modelado de objetos, cabe destacar la notación estándar UML (Unified Modeling Language), cuya última actualización es UML 1.2 a mediados de 1998. UML es una evolución de metodologías orientadas a objeto anteriores, como Booch, OMT y OOSE, tratando de unificar lo mejor de cada una de ellas. UML ha dado lugar a un potente lenguaje visual para expresar diseños orientados a objetos.

Cabe destacar, sin embargo, que UML es sólo un estándar de notación. Define diagramas para describir un sistema y el significado de dichos diagramas, pero no describe el proceso a seguir al desarrollar el software.

El ORB

Misión del ORB

Una parte fundamental de la arquitectura CORBA es el ORB, componente software cuyo fin es facilitar la comunicación entre objetos. El ORB se encarga de enviar las peticiones a los objetos y retornar las respuestas a los clientes que invocan dichas peticiones.

La principal característica del ORB es la transparencia, cómo facilita la comunicación cliente/servidor. Generalmente, el ORB oculta lo siguiente:

Estas características permiten a los desarrolladores centrarse en el dominio de la aplicación y no en la complejidad del sistema distribuido.

La idea de un ORB es la siguiente: cuando un componente de aplicación quiere utilizar un servicio proporcionado por otro componente, primero debe obtener una referencia para el objeto que proporciona ese servicio. Después de obtenerla, el componente puede llamar a los métodos en ese objeto, accediendo así a los servicios proporcionados por éste.

Cuando se crea un objeto CORBA también se crea una referencia para él. Cuando es utilizada por un cliente, la referencia siempre se refiere a dicho objeto para la que fue creada. Las referencias a objetos son inmutables y opacas, de esta forma un cliente no puede manipular una referencia y modificarla. Los clientes pueden obtener referencias a objetos de diversas formas:

Marshaling

Después de que el componente haya obtenido la referencia a un objeto, puede invocar métodos en dicho objeto. El ORB clasifica los parámetros, transformándolos a un formato estándar de red y posteriormente al formato entendible por el componente destino. También realiza el proceso inverso con los parámetros de salida.

Este proceso ocurre sin intervención del programador. Para la aplicación cliente, la llamada remota tiene la apariencia de una llamada local.

Independencia de la plataforma

Debido a que los parámetros se convierten a un formato independiente de la plataforma, la comunicación entre componentes es independiente de la plataforma. Un cliente en Macintosh puede invocar métodos en un servidor Unix. Las diferencias de hardware también resultan irrelevantes, ya que el ORB realiza las conversiones necesarias automáticamente.

El IDL

El lenguaje de definición de interfaz o IDL (Interface Definition Language) es un lenguaje sencillo utilizado para definir interfaces entre componentes. IDL sólo define interfaces, no implementaciones, asegurando la independencia del lenguaje de programación.

La especificación IDL asegura que los datos se intercambian correctamente entre lenguajes distintos. Por ejemplo, el tipo long puede corresponder con distintos tipos según el lenguaje. Es responsabilidad del compilador IDL definir dichos tipos de forma independiente.

El OMG ha definido correspondencias con lenguajes populares como C, C++, COBOL, Java, Smalltalk y Ada. En la Tabla 1 se muestra la correspondencia entre los tipos IDL y C++.

Tabla 1: Correspondencia para los tipos de datos básicos.
IDL C++
ShortCORBA::Short
LongCORBA::Long
Unsigned shortCORBA::UShort
Unsigned longCORBA::ULong
FloatCORBA::Float
DoubleCORBA::Double
CharCORBA::Char
BooleanCORBA::Boolean
OctectCORBA::Octect
AnyCORBA::Any

El registro de interfaz

Todas las aplicaciones basadas en CORBA necesitan acceder al sistema de tipos de IDL en tiempo de ejecución, ya que la aplicación necesita conocer los tipos de valores que se pasan como argumentos y los tipos de interfaces soportados por los objetos.

Algunas aplicaciones requieren sólo conocimiento estático del sistema IDL. En estos casos, la especificación IDL se compila y se integra en la aplicación. Si el sistema de tipos cambia, la aplicación debe reconstruirse.

Para aplicaciones que requieren conocimiento dinámico, CORBA proporciona el registro de interfaz, que permite recuperar información de interfaces en tiempo de ejecución. Un cliente puede ubicar un objeto desconocido, consultar su interfaz y construir una petición.

El modelo de objeto CORBA

Introducción

Toda arquitectura orientada a objetos define un modelo de objeto que describe cómo se representan los objetos. Al ser distribuida, CORBA presenta diferencias respecto a modelos tradicionales como C++ o Java.

Distribución de los objetos

Para un cliente CORBA, una llamada remota se percibe como una llamada local. La naturaleza distribuida es transparente. Sin embargo, la distribución aumenta la probabilidad de fallos, por lo que CORBA proporciona excepciones para manejar estas situaciones.

Referencias a objetos

Existen dos métodos para acceder a un objeto remoto:

Paso por referencia: el objeto se ejecuta en su proceso original, manteniendo la propiedad.

Paso por valor: el estado del objeto se copia al componente solicitante, modificándose sólo la copia.

Los adaptadores de objeto

El estándar CORBA describe adaptadores de objeto cuya tarea es servir de interfaz entre la implementación de un objeto y el ORB. El ORB proporciona infraestructura de comunicación y activación.

Actualmente CORBA proporciona el adaptador de objeto básico, que intenta ser multipropósito, aunque ha presentado limitaciones que el OMG continúa abordando.

El modelo de comunicaciones CORBA

Protocolos entre ORBs

La especificación CORBA es independiente de los protocolos de transporte; el estándar CORBA especifica GIOP (General Inter-ORB Protocol), que define un estándar para la comunicación entre componentes CORBA.

GIOP es un protocolo general. Existen protocolos que lo especializan para distintos transportes, como TCP/IP y DCE. Los vendedores también pueden definir protocolos propietarios.

El protocolo basado en GIOP más importante es IIOP (Internet Inter-ORB Protocol). Para ser conformes a CORBA, los fabricantes deben implementarlo. Esto asegura interoperabilidad entre productos de distintos vendedores.

Un ORB puede soportar múltiples protocolos y negociar cuál utilizar. Algunos fabricantes incorporan IIOP en servidores de bases de datos, herramientas de desarrollo o navegadores Web.

CORBA y el modelo de trabajo en red

Las aplicaciones CORBA se ejecutan sobre protocolos derivados de GIOP como IIOP, que a su vez funcionan sobre TCP/IP u otros protocolos de transporte. La arquitectura permite interconectar componentes que utilizan distintos protocolos mediante puentes.

CORBA crea una capa adicional (la capa de protocolo entre ORBs) sobre la capa de transporte, lo que favorece la interoperabilidad.

Clientes y servidores CORBA

En una aplicación cliente/servidor, el servidor proporciona servicios y el cliente los consume. En CORBA este modelo se mantiene, aunque un objeto puede actuar como cliente y servidor simultáneamente.

Un componente que implementa un objeto es considerado servidor CORBA y ejecuta métodos para otros componentes.

Stubs y skeletons

Tras definir interfaces IDL, el desarrollador utiliza un compilador IDL que genera client stubs y server skeletons. Estos actúan como “pegamento” entre las especificaciones independientes del lenguaje y el código de implementación.

Los client stubs proporcionan implementaciones falsas que delegan en el ORB la comunicación. Los server skeletons proporcionan la estructura sobre la que se implementa el servidor.

Estos conceptos evolucionaron hacia DII (Dynamic Invocation Interface) y DSI (Dynamic Skeleton Interface), que permiten invocaciones dinámicas sin conocimiento previo de las interfaces.

Ejemplo de programación en CORBA

En este apartado mostramos un sencillo ejemplo del desarrollo de una aplicación en CORBA, en concreto en Orbix 2.2 de IONA Technologies PLC sobre el sistema operativo Unix Solaris 5.5.1 de Sun Microsystems. Se trata de un contador cuyo valor podrá ser reseteado, incrementado, decrementado y consultado por los clientes.

Interfaz IDL

El código de la interfaz IDL de un contador, común a cualquier implementación CORBA, es el siguiente:


// Interfaz IDL a un contador
interface Contador
{
  // Devuelve el valor actual del contador
  long daValor ();

  // Pone el contador al valor especificado
  oneway void ponValor (in long valor);

  // Incrementa el valor del contador
  long incrementarValor (in short cantidad);

  // Decrementa el valor del contador
  long decrementarValor (in short cantidad);
};

Por defecto los métodos son bloqueantes. Para indicar que la operación sea no bloqueante se utiliza la cláusula oneway.

Los parámetros pueden declararse como in, out o inout.

La interfaz se compila generando tres ficheros:

Servidor

Fichero ContadorSC.h

#ifndef ContadorSC_h
#define ContadorSC_h

#include <Contador.hh>

class Contador_i
{
private:
  CORBA::Long _valor;

public:
  Contador_i(CORBA::Long valor = 0);

  virtual void ponValor(CORBA::Long valor,
    CORBA::Environment &IT_env = CORBA::default_environment);

  virtual CORBA::Long daValor(
    CORBA::Environment &IT_env = CORBA::default_environment);

  virtual CORBA::Long incrementarValor(
    CORBA::Short cantidad,
    CORBA::Environment &IT_env = CORBA::default_environment);

  virtual CORBA::Long decrementarValor(
    CORBA::Short cantidad,
    CORBA::Environment &IT_env = CORBA::default_environment);
};

DEF_TIE(Contador, Contador_i)

#endif
Fichero ContadorSC.cc

#include <ContadorSC.h>

Contador_i::Contador_i(long int valor)
{
  _valor = valor;
}

void Contador_i::ponValor(long int valor, CORBA::Environment &se)
{
  _valor = valor;
}

long int Contador_i::daValor(CORBA::Environment &se)
{
  return _valor;
}

long int Contador_i::incrementarValor(short int cantidad, CORBA::Environment &se)
{
  _valor = _valor + cantidad;
  return _valor;
}

long int Contador_i::decrementarValor(short int cantidad, CORBA::Environment &se)
{
  _valor = _valor - cantidad;
  return _valor;
}
Fichero main.cc

#include <ContadorSC.h>

main()
{
  Contador_var Servidor =
    TIE_Contador(Contador_i)(new Contador_i);

  try
  {
    CORBA::Orbix.impl_is_ready("contador", CORBA::Orbix.INFINITE_TIMEOUT);
  }
  catch (const CORBA::SystemException& codigo)
  {
    cerr << "Excepcion CORBA al registrar el servidor: "
         << codigo;
  }
}

Cliente

Fichero ContadorCC.cc

#include <Contador.hh>

int main()
{
  Contador_var MiContador;
  int operacion = 0;
  short int cantidad = 0;

  try
  {
    Contador::_bind(":contador");
  }
  catch (const CORBA::SystemException& codigo)
  {
    cerr << "Ha fallado la comunicación con el objeto: "
         << codigo << endl;
    return 0;
  }

  while (operacion != 5)
  {
    cout << "1. Resetear" << endl;
    cout << "2. Incrementar" << endl;
    cout << "3. Decrementar" << endl;
    cout << "4. Mostrar valor" << endl;
    cout << "5. Salir" << endl;

    cin >> operacion;

    switch (operacion)
    {
      case 1:
        MiContador->ponValor(0);
        break;

      case 2:
        cin >> cantidad;
        MiContador->incrementarValor(cantidad);
        break;

      case 3:
        cin >> cantidad;
        MiContador->decrementarValor(cantidad);
        break;

      case 4:
        cout << MiContador->daValor() << endl;
        break;

      case 5:
        return 1;
    }
  }
}

Alternativas a CORBA

La eficiencia de CORBA suele ser menor que implementaciones a bajo nivel con sockets, debido al procesamiento adicional. Sin embargo, dichas soluciones son más complejas y menos portables.

CORBA presenta similitudes con DCE basado en RPC (Remote Procedure Call), aunque CORBA es orientado a objetos y permite encapsular aplicaciones y datos.

También comparte principios con OLE (Object Linking and Embedding) de Microsoft y con COM, que extendió la integración a múltiples plataformas. El OMG trabajó en la interoperabilidad entre CORBA y COM.

Otro ORB conocido es Java RMI (Remote Method Invocation), recomendable para aplicaciones distribuidas en Java, aunque limitado a ese lenguaje.

Volver al listado de artículos