3.1 El lenguaje de especificación IDL

Anuncio
3.1 El lenguaje de especificación IDL
El lenguaje de especificación IDL
n
n
n
Permite especificar interfaces remotas en un
lenguaje neutral
El compilador (preprocesador) de IDL genera código
para el lenguaje(s) destino(s) (para poder invocar las
operaciones e implementar las interfaces)
Mappings estandarizados para un buen número de
lenguajes (C, C++, Java, COBOL, Smalltalk, Ada,
etc.)
n
n
Cada vez se van añadiendo más ...
Actualmente IDL es un lenguaje relativamente
extenso
n
Veremos lo esencial ...
Reglas léxicas (1)
n
Ficheros fuente IDL
n
n
Deben tener la extensión .idl
Son preprocesados por el preprocesador de C++
n
n
Se puede usar #define, #include, #ifdef, #ifndef,
#endif, etc.
Comentarios
// Esto es un comentario de una línea.
/* Esto es un comentario
de varias líneas. */
n
Palabras reservadas
n
n
Casi todas en minúsculas
Algunas excepciones: TRUE, FALSE y Object
Reglas léxicas (y 2)
n
Identificadores
n
n
Deben comenzar con un carácter alfabético seguido por
cualquier número de caracteres alfabéticos, dígitos o “_”
(subrayado)
No se distingue entre mayúsculas y minúsculas, pero deben
utilizarse consistentemente
n
n
n
Si definimos el identificador MAX, a partir de ese momento
siempre debemos utilizar MAX y no Max, max, etc.
Objetivo: permitir mappings de IDL tanto a lenguajes que
distinguen entre mayúsculas y minúsculas en identificadores
(ej.: C++, Java) como a otros que no (ej.: Ada)
Es importante evitar nombres de identificadores que sean
palabras reservadas en algún de lenguaje de
implementación (ej.: package, self)
Tipos predefinidos (1)
n
Numéricos
Tipo
short
Rango
Tamaño
-215.. 215-1
>= 16 bits
long
-231.. 231-1
>= 32 bits
long long
-263.. 263-1
>= 64 bits
unsigned short
0.. 216-1
>= 16 bits
unsigned long
0.. 232-1
>= 32 bits
unsigned long long 0.. 264-1
float
IEEE Precisión simple
double
IEEE Precisión doble
long double
IEEE Precisión extendida
>= 64 bits
>= 32 bits
>= 64 bits
>= 79 bits
Tipos predefinidos (2)
n
Numéricos (cont)
n
n
El mapping de IDL a un lenguaje de implementación debe
preservar el tamaño, pero no necesita mantener el rango
¿ Por qué los tamaños pueden ser mayores ?
n
n
¿ Por qué algunos mappings no mantienen los rangos
n
n
Ej.: algunas arquitecturas (CPUs) no disponen de caracteres de
8 bits o enteros de 16 bits, y se mapean a tipos con tamaños
mayores
Ej.: Java no tiene enteros sin signo, y por tanto, mapea los
tipos IDL long y unsigned long al tipo Java int
long long, unsigned long long, long double se
añadieron en CORBA 2.1, por lo que los ORBs
antiguos no los soportarán
Tipos predefinidos (3)
n
Caracteres
n
n
n
n
char: 8 bits
wchar: tamaño dependiente de la implementación
Codificación: dependiente de la implementación en ambos casos,
pero el ORB se preocupará de realizar la conversión (si puede)
cuando cliente y servidor utilizan distintos sistemas de codificación
Cadenas de caracteres
n
n
string y wstring. No pueden contener carácter 0
Ejemplos
string<10> // string acotado (10 char como máximo)
string // string no acotado
wstring<10> // wstring acotado (10 wchar como máximo)
wstring // wstring no acotado
n
n
string<x> y wstring<x> son tipos propios (distintos de
string y wstring)
wchar y wstring se añadieron en CORBA 2.1, por lo que
los ORBs antiguos no los soportarán
Tipos predefinidos (y 4)
n
octet
n
n
n
n
boolean
n
n
8 bits
No se realiza ninguna conversión entre cliente y servidor
Utilidad: transferir datos binarios
Proporciona los valores TRUE y FALSE
any
n
n
n
En un tipo “contenedor”: un valor de tipo “any” puede
contener un valor de cualquier tipo (predefinido o definido
por el usuario)
Es seguro (type-safe) y permite instrospección
Utilidad: cuando en una operación no se conoce el tipo de
uno de sus parámetros en tiempo de compilación (ej.:
servicio de eventos)
typedef
n
Permiten crear un nuevo nombre para un tipo
typedef short Year;
typedef short Temperature;
typdef Temperature Temp; // ¡ Mal estilo !
n
n
Permiten realizar especificaciones más claras
Se deben evitar alias innecesarios (ej.: la tercera
definición)
n
n
Es confuso
Puede causar problemas en los mappings que utilicen reglas
estrictas de equivalencia de tipos
Enumeraciones
n
Ejemplo
enum Color {red, green, blue, yellow, white};
n
A diferencia de C, Color es un tipo y el nombre del
tipo es obligatorio
typedef enum {red, green, blue} Color; // ¡ Error !
n
Los valores de un tipo deben ser únicos dentro de su
ámbito
enum InteriorColor {red, green, blue};
enum ExteriorColor {blue, yellow, white}; // ¡ Error !
n
A diferencia de C++, no se les puede dar valores
enum Color {red=0, green=8, blue=16}; // ¡ Error !
Estructuras
n
Ejemplo
struct Date {
short year;
short month; // 1-12
short day; // 1-31
};
n
A diferencia de C, Date es un tipo y el nombre del
tipo es obligatorio
typedef struct {
short year;
short month; // 1-12
short day; // 1-31
} Date; // ¡ Error !
Union (1)
n
Ejemplo
union Token switch(Color) {
case blue:
float floatValue;
case red:
case green:
long longValue;
default:
string stringValue;
};
n
n
El discriminador tiene que ser un tipo entero, char,
boolean o una enumeración
A diferencia de C
n
n
Token es un nombre de tipo y el nombre del tipo es
obligatorio
Utilizan discriminador con case y quizás un default
Union (2)
n
No se debe utilizar default ni más de un case por
campo
n
n
Complica algunos mappings (ej.: C++)
No se debe utilizar una union para simular
sobrecarga ...
enum OrderDetailInformationKind {text, numeric, none};
union OrderDetailInformation switch(OrderDetailInformationKind) {
case text:
string description;
case numeric:
long index;
};
interface Order {
void setOrderDetailInformation(in OrderDetailInformation info);
};
Union (y 3)
n
... es mejor estilo
interface Order {
void setDescription(in string description);
void setIndex(in long index);
};
n
Uso idiomático: simular operaciones con parámetros
opcionales
union AgeOptional switch(boolean) {
case TRUE:
unsigned short age;
};
n
Consejo general
n
No usar union
Vectores
n
Se pueden definir vectores de una o varias
dimensiones
typedef Date DateVector[10]; // Tipo “DateVector”
typedef string StringMatrix[10][20]; // Tipo “StringMatrix”
n
n
Se debe usar typedef
A diferencia de otros lenguajes, no soporta vectores
abiertos (“open arrays”)
typedef string StringMatrix[][20]; // ¡ Error !
n
Hay que tener cuidado cuando se pasan índices de
arrays en invocaciones remotas
n
Es preciso definir una convención
Secuencias
n
Las secuencias son vectores de longitud variable
typedef sequence<Color> Colors; // Secuencia no acotada
typedef sequence<Date, 10> Dates10; // Secuencia
// acotada (10 fechas como máximo)
n
n
Se debe usar typedef
¿ Cuándo usar secuencias y cuándo usar vectores ?
n
n
n
n
n
Una lista de cosas con número fijo de elementos => vector
Una lista de cosas con número variable de elementos =>
secuencia
Cadenas de caracteres de tamaño fijo => vector de char
Vectores dispersos (“sparse arrays”) => secuencias
Estructuras de datos recursivas => secuencias
Tipos de datos recursivos
n
IDL no tiene punteros, pero permite definir
estructuras recursivas
struct Node {
long value;
sequence<Node, 2> children;
}; // Un árbol binario
n
Restricciones
n
n
n
Sólo para struct y union
La recursividad se expresa con una secuencia anónima del
tipo incompleto (recursivo)
No se permite recursividad mutua
Constantes y literales
n
Se pueden definir de cualquier tipo predefinido
(excepto any) o de un enumerado
const
const
const
const
const
const
const
const
const
const
const
n
short MAX_TEMP = 35;
short MIN_TEMP = -10;
short AVG_TEMP = (MAX_TEMP+MIN_TEMP)/2;
float PI = 3.1415926;
double MAXIMUM = 1E10;
char FIRST_LOWER_CASE_LETTER = ‘a’;
char NULL = ‘\0’;
string LAST_WORDS = “My God, it’s full of stars !”;
octet MSB_MASK = 0x10; // Hexadecimal (tb. en enteros)
octet MSB_MASK2 = 0100; // Octal (tb. en enteros)
Color FAVORITE_COLOR = blue;
Las expresiones pueden utilizar
n
n
+, -, *, /, % (con enteros y reales, excepto %)
|, &, ^, <<, >>, ~ (con enteros)
Interfaces (1)
n
Ejemplo
interface Thermostat {
typedef short Temperature;
typedef string Location;
exception InvalidTemperature {
Temperature selectedTemperature;
Temperature minimumPermitedTemperature;
Temperature maximumPermitedTemperature;
};
Tempeature getTemperature();
void setTemperature(in Temperature value)
raises(InvalidTemperature)
Location getLocation();
};
Interfaces (y 2)
n
Un interfaz es un tipo
interface Controller {
typedef sequence<Thermostat> ThermostatList;
ThermostatList findAllThermostats();
Thermostat findThermostatByLocation(
in Thermoter::Location loc);
};
n
Los objetos remotos se pasan por referencia
n
n
En el anterior ejemplo, el cliente obtiene una referencia a un
proxy del objeto remoto. ¡¡¡ Los objetos remotos no se
mueven !!!
Existe la referencia especial “nil”
n
Utilidad: indicar opcionalidad (pasar “nil” en un parámetro que
admita un objeto remoto) o indicar “no encontrado”
(findThermostatByLocation)
Operaciones (1)
n
n
n
Pueden devolver excepciones
No se pueden sobrecargar
Atributos direccionales
n
n
n
n
in: el valor del parámetro se lo envía el cliente al servidor
out: el valor del parámetro se lo envía el servidor al cliente
inout: el valor del parámetro se lo envía el cliente al
servidor, quien posiblemente lo modifica, y se lo envía otra
vez al cliente (machacando el valor anterior)
Estilo
n
n
Si una operación acepta uno o más parámetros in y
devuelve un solo resultado => el resultado se debería
devolver como valor de retorno
Si una operación tiene varios valores de retorno con la
misma importancia => usar out para los correspondientes
parámetros y void como tipo de retorno
Operaciones (y 2)
n
Estilo
n
Si una operación retorna varios valores, pero uno de ellos
tiene más importancia => devolver este último como valor
de retorno y el resto como out
boolean getNext(out ValueType value);
n
Usar los parámetros inout con precaución
n
n
n
Se asume que el llamador no quiere conservar el valor
Eficientes cuando se pasan valores grandes
Ejemplo
invertMatrix (inout Matrix aMatrix);
Excepciones definidas por el usuario (1)
n
Ejemplo
exception InvalidTemperature {
Temperature selectedTemperature;
Temperature minimumPermitedTemperature;
Temperature maximumPermitedTemperature;
};
n
n
Pueden no tener campos
No admiten herencia
n
n
n
Complicaría algunos mappings
No se pueden usar como campos de tipos definidos
por el usuario
Si una operación puede levantar varias excepciones,
se separan por comas en la cláusula raises
void foo() raises(Exception1, Exception2);
Excepciones definidas por el usuario (2)
n
Mal estilo
interface DataBase {
typedef sequence<Row> RowList;
typedef string Query;
exception NoRow {
Query failedQuery;
};
RowList lookup(in Query q) raises(NoRow);
};
n
n
n
Puede ser normal que no exista ningún registro que cumpla
la query
El campo failedQuery no aporta nada
¿ Por qué falló la query ?
n
¿ no había filas que cumplieran la condición ?, ¿ no era
sintácticamente correcta ?, ¿ falló la base de datos ?
Excepciones definidas por el usuario (y 3)
n
Buen estilo
interface DataBase {
typedef sequence<Row> RowList;
typedef string Query;
exception SyntaxError {
unsigned short position;
};
exception DataBaseInternalError {
string explanation;
};
RowList lookup(in Query q)
raises(SyntaxException, DataBaseInternalError);
};
Excepciones del sistema
n
CORBA define un buen número de excepciones del
sistema
n
n
n
Cualquier operación puede levantar una excepción del
sistema
Nunca debe levantarlas el programador
Todas las excepciones tienen la siguiente definición
enum completion_status {
COMPLETED_YES, COMPLETED_NO, COMPLETED_MAYBE
};
exception <SystemExceptionName> {
unsigned long minor;
completion_status completed;
};
n
Ej.: COMM_FAILURE, NO_MEMORY, INTERNAL,
OBJ_ADAPTER, INV_OBJREF, etc.
Atributos
n
Ejemplo
interface Thermostat {
typedef short TemperatureType;
typedef string LocationType;
attribute TemperatureType temperature;
readonly attribute LocationType location;
};
n
Los atributos no son el estado del objeto que
implemente el interfaz
n
n
n
n
Sólo definen operaciones para leer y escribir valores
Los atributos readonly sólo definen operaciones de lectura
Inconveniente: no pueden tener cláusula raises
Consejo: no usuarlos
Declaraciones incompletas
n
Ejemplo
interface Husband;
interface Wife {
Husband getSpouse();
};
interface Husband {
Wife getSpouse();
};
Herencia (1)
n
Se permite herencia de interfaz
interface Thermometer {
typedef short Temperature;
typedef string Location;
Temperature getTemperature();
Location getLocation();
};
interface Thermostat : Thermometer {
void setTemperature(in Temperature t);
};
n
.. y en consecuencia se soporta el polimorfismo
interface Controller {
Thermometer findByLocation(in Location l);
void add(in Thermometer t);
};
Herencia (y 2)
n
Todos los interfaces derivan implícitamente de
Object
n
n
n
Un interfaz que deriva de otro no puede volver a
declarar (redefinir) una operación del padre
n
n
En un parámetro de tipo Object se puede pasar una
referencia a un objeto remoto de cualquier tipo
La sintaxis de IDL no permite que un interfaz derive
explícitamente de Object
No tiene sentido en herencia de interfaz
Se permite herencia múltiple
interface AmphibiousVehicle : LandVehile, WaterVehicle
// ...
};
n
{
No se puede heredar un mismo atributo u operación de más
de un interfaz base
Módulos
n
Similares a los namespaces de C++
module es { module udc { module fbellas {
module corba { module clock { module idl {
struct TimeOfDay {
// ...
};
interface Clock {
TimeOfDay getTimeOfDay();
};
}; }; }; }; }; };
n
n
Evitan conflictos de nombres
Se pueden cerrar y volver a abrir
Tipos anónimos (1)
n
Con CORBA 2.4, los tipos anónimos se
consideran desaprobados
n
n
n
n
Complican mappings
Se consideran desaprobados (“deprecated”)
En consecuencia, no se deben usar
Una mala definición ...
struct Order {
long identifier;
string<100> description; // ¡ deprecated !
};
n
Una buena definición ...
typedef string<100> OrderDescription;
struct Order {
long identifier;
OrderDescription description;
};
Tipos anónimos (y 2)
n
n
Hasta CORBA 2.3 (inclusive) no queda más remedio
que usar secuencias anónimas para los tipos
recursivos
CORBA 2.4 añade declaraciones incompletas para
struct y union
n
Ya no es preciso usar tipos anónimos en ningún caso
typedef struct Node;
typedef sequence<Node, 2> ChildSequence;
struct Node {
long value;
ChildSequence children;
};
Identificadores de repositorio (1)
n
n
n
n
El compilador de IDL genera un identificador de
repositorio por cada identificador
Con el identificador se puede acceder a su definición
(introspección) por medio del Repositorio de
Interfaces
¡ El identificador debe ser único !
Existen tres tipos de formatos de identificadores
n
n
n
n
IDL
DCE UUID (Universally Unique IDentifier)
LOCAL
El formato IDL es el formato que utiliza el compilador
de IDL por defecto y es el usado normalmente
Identificadores de repositorio (y 2)
n
Ejemplo
module TCS { // IDL:TCS:1.0
typedef short Temperature; // IDL:TCS/Temperature:1.0
interface Thermometer { // IDL:TCS/Thermometer:1.0
Temperature getTemperature();
// IDL:TCS/Thermometer/getTemperature:1.0
};
};
n
¿ Y qué ocurre si alguien más ha elegido el nombre
TCS para un módulo ?
#pragma prefix “es.udc”
module TCS { // IDL:TCS:1.0
typedef short Temperature; // IDL:es.udc/TCS/Temperature:1.0
interface Thermometer { // IDL:es.udc/TCS/Thermometer:1.0
Temperature getTemperature();
// IDL:es.udc/TCS/Thermometer/getTemperature:1.0
};
};
n
Otra posibilidad es usar nombres de módulos del
estilo “es.udc....”
Ámbito (1)
n
Crean ámbito (scope)
n
n
n
módulos, interfaces, estructuras, unions, excepciones y listas de
parámetros
Dentro de un ámbito los nombres de identificadores deben ser
únicos
Ejemplo
module M1 {
typdef short T1;
interface I1 {
typedef long T2;
// ...
};
};
module M2 {
interface I2 {
void foo(in M1::T1 par1, in M1::I1::T2 par2);
};
};
Ámbito (y 2)
n
Error típico
interface Thermostat {
typedef short Temperature;
exception InvalidTemperature {
// ...
};
void setTemperature(in Temperature temperature) // ¡ Error !
raises(InvalidTemperature)
};
Descargar