Lenguaje OMG/IDLIntroducciónEl lenguaje OMG/IDL es uno de los pilares de la plataforma OMA de OMG, y en especial de CORBA.Gracias a este lenguaje descriptivo podemos especificar las interfaces de nuestros módulos CORBA, sin ligarnos a ningún lenguaje concreto. Además es un lenguaje muy adecuado para el diseño del sistema ya que permite pensar en el diseño del sistema, sin tener que descender a detalles de implementación. Para evitar ambiguedades a nivel de diseño es un lenguaje fuertemente tipado, al estilo de Java. Es un lenguaje cuya sintaxis está bastante cercana a la de ANSI C++ o Java, al ser orientado a objetos. Tiene facilidades como la definición de módulos e interfaces, herencia de interfaces o excepciones. Es un lenguaje lo suficientemente descriptivo como para poder detallar interfaces de objetos que van a ser distribuidos. Pasamos a describir el lenguaje con mayor detalle a continuación, así como ejemplos de los principales traducciones de OMG IDL a lenguajes como C, C++ y Java. Descripción del lenguajeLa mejor forma de entender el lenguaje es mediante un ejemplo que iremos explicando a lo largo de este apartado.El ejemplo que utilizaremos luego será implementado como uno de los ejemplos del curso, por lo que es necesario que los participantes en el curso se familiaricen con él.
1: // Módulo de intercambio de mensajes entre usuarios
2: module Mensajes {
3: interface comun {
4: // Version de la aplicacion
5: readonly attribute string version;
6:
7: // Nombre de usuario
8: typedef string usuario;
9: // Lista de usuarios
10: typedef sequence
Módulos e interfacesEste ejemplo es bastante completo y nos va a permitir profundizar en diferentes aspectos de OMG IDL.La primero que observamos es la forma de encapsular en módulos las interfaces. Un módulo debe de ser un conjunto de interfaces que proporcionan una funcionalidad concreta dentro del sistema. En nuestro caso este módulo es el encargado de definir el módulo de Mensajes de una herramienta de trabajo cooperativo.
Dentro del módulo hemos definido dos interfaces: una para los clientes y
otra para el servidor central. La arquitectura sigue los esquemas
centralizados, es decir, que un servidor central controla la forma de
interactuar entre los diferentes clientes. Pero también se pueden obtener
las interfaces a otros clientes y comunicarnos con ellos de forma
directa. Operaciones y tipos de datosLas funciones se agrupan en interfaces cuando tienen un proposito común.Dichas funciones tienen parámetros de entrada, con sus tipos correspondientes y parámetros de salida. Es necesario especificar el parámetro de retorno, aunque este sea "void". Es característicos de OMG/IDL que los parámetros que se pasan a la función pueden ser de tres tipos:
Pero en los parámetros "out" y "inout" aparece el problema de que, el cliente puede reservar una cantidad de memoria para el parámetro, cantidad que puede ser modificada por el objeto para que entre en el parámetro la respuesta. En el estandar se han dividido 20 tipos de parámetros en 6 tipos de paso de parámetros. Por ejemplo, para parámetros de longitud fija (incluyendo las estructuras), el llamante reserva y libera el espacio excepto en el caso de "any". Las referencias a objetos también son gestionadas en el cliente. Pero por ejemplo, si el parámetro es "inout", la implementación del objeto va a invocar la operación CORBA::Object_release en el valor original para reasignar el parámetro (algo que también afecta en el lado del cliente). Para guardar el valor original de la referencia al objeto, deberemos utilizar CORBA::duplicate antes de invocar la operación. Hay casos en los parámetros "out" y "inout" en los que la implementación debe de reservar la memoria, pero debe ser liberada en el cliente. Dentro del estandar estas detallados todos los casos y hay que ser cuidadoso para evitar agujeros de memoria en nuestras apliaciones.
Los tipos de estos datos son los que solemos encontrarnos en cualquier
lenguaje de programación: integer (signed/unsigned long, short), float,
double, boolean, octet, any. Por último comentar que existe un tipo especial de operación, aquellas del tipo "oneway". Son operaciones que se invocan sin esperar ningun valor de retorno, no siendo bloqueantes. Por ello en este tipo de operaciones el tipo de retorno ha de ser "void" y todos los parámetros han de ser del tipo "in". Un ejemplo de este tipo de ooperación lo observamos en la línea 27, donde el servidor envía las alarmas a los clientes, sin esperar que estos le respondan nada. ExcepcionesAlgo importante en la invocación de operaciones sobre objetos CORBA es que, aunque para el desarrollador sean invocaciones comunes sobre objetos, el mecanismo para sus ejecución es complejo: han de pasar por los cabos del cliente, por el ORB, por el adaptador de objetos, encontrar el objeto adecuado, viajar por los cabos del servidor, realizar la invocación sobre el objeto y recorrer el mismo viaje de vuelta.Es sencillo que en todo este trasiego puedan aparecer problemas. Y para informar al cliente de dichos problemas aparecen las excepciones. Ante problemas en la invocación de estas operaciones, el ORB nos puede devolver excepciones de diferentes tipo, según el problema aparecido.
Pero es más dentro de nuestro código también podemos crear excepciones para
la gestión de errores, o para comunicar situaciones excepcionales. HerenciaLa herencia es un mecanismo de reutilización de funcionalidad. En nuestro caso la utilizamos para definir la interfaz de un operador, que es un cliente con una operación más, la de recibir información de conexiones.
REVISAR NUMEROS DE LINEAMapping a CAl no tener el lenguaje C objetos ni excepciones, en el mappping de OMG/IDL a C en todas las operaciones aparecen el objeto sobre el que se va a invocar, y una variable de contexto para recoger información sobre las excepciones.La carencia en C de espacios de nombres obliga a nombres de la forma "CORBA_object" y con ello, aparece el problema de posibles colisiones de nombres. Un ejemplo de mapping sencillo podría ser:
interface ejemplo {
long operacion (in string arg);
};
Este interfaz en IDL genera en C (partes relevantes):
typedef CORBA_Object ejemplo;
extern CORBA_long operacion (
ejemplo o, CORBA_string arg, CORBA_Enviroment *ev);
Queda patente del ejemplo como en cada operación, hay que especificar el
objeto sobre el que se va a ejecutar la operación, así como el entorno por
el que se pasarán las excepciones.Los tipos básicos no se traducen directamente a tipos en C, ya que los tipos en C pueden variar de una arquitectura a otra (número de bits, forma de ordenación de los bytes ...). Por ello por ejemplo el tipo IDL "long" se mapea a "CORBA_long" en C, y no a un long directamente. Para traducir el mecanismo de herencia lo que se hace, como en C no existe la herencia, es incluir dentro de la traducción todos los elementos de la interfaz, y todos los de las interfaces de los que hereda. Como ya dijimos el manejo de excepciones se realiza utilizando variables de entorno "CORBA_Enviroment". Este mismo mecanismo es el que se utiliza en el caso de los compiladores de C++ que aún no tuvieran soporte para excepciones. Mapping a C++La traducción de OMG/IDL es más directa a C++ que a C, a pesar de que en cuando se publicó el mapping de OMG/IDL a C++ aún no estaba aprobado el estandar ANSI C++, lo que obligó a dar rodeos para aspectos (p.e. string) que hoy serían mucho más sencillo.Siguiendo con el mismo ejemplo anterior:
interface ejemplo {
long operacion (in string arg);
};
Este interfaz en IDL genera en C++ (partes relevantes):
class ejemplo : virtual public CORBA::Object {
virtual CORBA::Long operacion( const char* arg ) = 0;
}
Todos las interfaces se convierten en objetos CORBA por el mecanismo de la
herencia, hecho que muestra que todos los objetos CORBA tienen una
funcionalidad común, con operaciones como:
Normalmente C++ mos proporciona el "casting" de generalización. Con la operación de _narrow podemos transformar un "CORBA::Object" en un objeto concreto. Como vemos la operación de la interfaz es definida como una operación abstracta pura, es decir, que para implementar este objeto estamos obligados a implementar esta operación. Normalmente para implementar la interfaz lo que se hace es heredar de la clase ejemplo (class ejemploImp:virtual public ejemplo) e implementar la operación.
Como comentamos en la introducción a IDL, uno de los problemas a la hora de
desarrollar con CORBA era la gestión de memoria, en concreto con los
parámetros "inout" y "out". Dentro de los ejemplos profundizaremos más en el uso de IDL en C++, como se implementan los interfaces y como se usan los objetos. Mapping a JavaEl mapping a Java es el último que se produjo, finales de 1997, y es quizás el más directo de todos, debido al soporte que da Java a la programación orientada a objetos, el uso de interfaces, ...Tomando el ejemplo anterior tenemos:
interface ejemplo {
long operacion (in string arg);
};
Este interfaz en IDL genera en Java (partes relevantes):
public interface ejemplo extends org.omg.CORBA.CORBject {
int operacion(java.lang.String arg);
}
Este ejemplo es muy parecido al de C++, pero como Java tiene la construcción
sintáctica "interface" la traducción es todavía más inmediata.Uno de los problemas que presenta Java es que no soporta la herencia múltiple. Esto obliga a que por ejemplo, si la clase que implementa la interfaz ya hereda de alguna otra, no podemos heredar de nuevo de la clase ejemplo (no heredamos directamente de la interfaz "ejemplo" si no de la clase "ejemploStub"). Cuando OMG definió como se pasaba de IDL a Java, Java estaba ya prácticamente estandarizado por lo que el "mapping" fue sencillo. Los problemas de gestión de memoria aquí no aparecen ya que, Java gestiona de forma automática la memoria con el recolector de basura. ResumenHasta el momento hemos hecho una introducción a como se traduce de OMG/IDL a C, C++ o Java. Hemos visto que el soporte de objetos de C++ y Java facilita su traducción.A continuación pasamos a describir las herramientas básicas que utilizaremos para desarrollar los ejemplos, para a continuación pasar a programar utilizando Java. |