CORBA Mapeo del IDL en lenguajes de programación Mapeo del

Anuncio
Mapeo del IDL en lenguajes de
programación
CORBA
➨
Lenguajes:
–
–
»
–
C
Java
C++
Ada-95, SmallTalk, COBOL, Lisp, Phyton, IDLscript
Angel García Baños
Escuela de Ingeniería de Sistemas y Computación
Universidad del Valle
27 de Noviembre de 2002
CORBA 3
AGB
Mapeo del IDL en lenguaje C++
Mapeo del IDL en lenguaje C++
■
CLIENTE
STUB en
C++
Especificación de la
interfase en IDL
■
Compiladores
■
Object Request Broker (ORB)
■
SKELETO
N en C++
■
IMPLEMENTACIÓN DEL
OBJETO
3
AGB
2
Mapeo del IDL en lenguaje C++
(Tipos básicos)
IDL
C++
short
long
long long
unsigned short
unsigned long
unsigned long long
float
double
long double
char
wchar
string
wstring
boolean
octet
any
CORBA::Short
CORBA::Long
CORBA::LongLong
CORBA::UShort
CORBA::ULong
CORBA::ULongLong
CORBA::Float
CORBA::Double
CORBA::LongDouble
CORBA::Char
[(un)signed] char
CORBA::WChar
int
o wchar_t
char * // Por mantener compatibilidad con C
CORBA::WChar *
CORBA::Boolean
bool o [(un)signed] char
CORBA::Octet
[(un)signed] char
CORBA::Any AGB
5
Usualmente se mapea a
Es muy eficiente, aunque a la vez es largo y complejo de
entender. Se prefirió así, ya que siempre se puede diseñar
una capa superior (wizards, etc.) que facilite las cosas.
Es consistente. Todo lo que se aprenda para strings es
válido para otros tipos de longitud variable.
Tiene chequeo de tipos. No se requieren moldes (casts) y
la mayoría de los errores de tipos se detectan al compilar.
Es fácil de memorizar, ya que aunque cada clase tiene
muchas funciones miembro, la mayoría no las usa el
programador, sino que son para conversiones automáticas
de tipos.
Proporciona facilidades para compiladores que no sean
estrictamente ANSI C++.
AGB
4
Mapeo del IDL en lenguaje C++
(Identificadores)
■
Los identificadores se preservan al pasar de IDL a
C++. Solo en caso de conflicto con palabras
reservadas, se les añade el prefijo _cxx_.
enum colores {if, while, class}; // IDL
enum colores {_cxx_if, _cxx_while, _cxx_class}; // C++
■
No se deben usar identificadores con doble
subrayado (ej: hola__mundo), ya que pueden
colisionar con palabras reservadas.
AGB
6
Mapeo del IDL en lenguaje C++
(Módulos)
■
Los module de IDL se mapean en namespace de
C++ (si el compilador no soporta namespace,
entonces se mapean en class).
Mapeo del IDL en lenguaje C++
(Interfases)
■
module A
// IDL
{
module B { ... };
};
– class Nombre_ptr
puntero simple al objeto.
puntero al objeto que hace el manejo
– class Nombre_var
de memoria de forma automática.
Se convierte en:
namespace A
// C++
{
namespace B { ... };
};
■
■
7
AGB
Mapeo del IDL en lenguaje C++
(Interfases)
■
Está prohibido manejar directamente la interfase a un
objeto, excepto a través de esas dos clases.
■
■
■
Los _ptr son punteros normales, que apuntan a objetos
remotos. Al acabar de usarlos hay que liberarlos con
CORBA::release()
Los _var son punteros inteligentes: Cuando salen fuera de
ámbito, su destructor libera la memoria referenciada.
En ambos casos (_ptr y _var) se debe usar el operador
flecha -> para acceder a los miembros de la interfase.
■
9
Mapeo del IDL en lenguaje C++
(Tipos de longitud variable)
La forma como internamente se hace el manejo
de memoria con parámetros de longitud variable:
■
SERVIDOR
char *copyright()
{
obj->invoke(“copyright”);
}
■
while(!done)
{
op = get_request();
char *s = invoke(op);
Se pueden usar los dos mapeos, con la ventaja de que el _var
se encarga de liberar la memoria usada cuando se sale la
variable fuera de su ámbito. Si la estructura, la unión o el
array son de tamaño fijo, también se genera la clase _var
correspondiente, pero entonces
no libera memoria.
10
AGB
Los strings pueden ser limitados o ilimitados, pero es
responsabilidad del programador no salirse de los
límites.
Está prohibido usar new y delete para manejar la
memoria de strings dinámicos. En su lugar, usar:
{
// ...
static
static
static
static
static
static
}
}
send(s);
CORBA::string_free(s);
CORBA::string_free(s);
AGB
clase wrapper _var
CORBA::String_var
CORBA::Any_var
class foo_var
class foo_var
class foo_var
class foo_var
class foo_var
namespace CORBA
char *copyright()
{
char *s = string_dup(...);
return s;
unsigned len = recv_len();
char *s = string_alloc(len);
recv(s);
return s;
C++
char *
CORBA::Any
class foo_ptr
struct foo
class foo
class foo
typedef X foo[10]
Mapeo del IDL en lenguaje C++
(strings)
CLIENTE
Objet_var obj = ...;
char *s = obj->copyright();
8
Se crean clases _var para los tipos de longitud variable, para
facilitar el manejo de memoria:
IDL
string
any
interface foo
struct foo
union foo
typedef sequence<X> foo
typedef X foo[10]
AGB
■
Se pueden usar cualquiera de los dos tipos, incluso
ambos a la vez.
Con las referencias se pueden hacer las operaciones
duplicate(), release(), is_nil() y narrow() que veremos
AGB
mas adelante.
Mapeo del IDL en lenguaje C++
(Tipos de longitud variable)
Nombre a; // MAL
Nombre *a; // MAL
Nombre &a; // MAL
Nombre_var a; // BIEN
Nombre_ptr a; // BIEN
■
Las interfases se convierten en clases. Cuando se
obtiene una referencia a un objeto, lo que se tiene
desde el punto de vista del programador es un
puntero a su interfase. Estos punteros se manejan
como clases de dos tipos (suponiendo que la interfase
se llame Nombre):
11
}
char * string_alloc(Ulong leng); // Reserva 1 char mas para el NULL
char * string_dup(const char *);
void string_free(char *);
WChar * wstring_alloc(Ulong leng);
// Reserva 1 WChar mas
WChar * wstring_dup(const WChar *);
void wstring_free(WChar *);
AGB
12
Mapeo del IDL en lenguaje C++
(strings)
■
Mapeo del IDL en lenguaje C++
(strings)
Ejemplo de clase String_var (es similar para otros
tipos distintos al string):
■
CORBA::String_var s;
cout << s; // Core dump (string NULL)
Class String_var
{
public:
String_var(); // inicializa el string a NULL
String_var(char *); // Toma posesión del string (shallow copy)
String_var(const char *); // No toma posesión (deep copy)
String_var(const String_var &); // No toma posesión (deep copy)
~String_var(); // Destruye el string propio
// ...
private:
char *s;
HOLA MUNDO\0
};
AGB
■
CORBA::String_var s(CORBA::string_dup(“Hola”));
} // OK. No hay memory leak ya que ~String_var llama a string_free()
■
Otro ejemplo:
const char *mensaje = “Hola”;
{
CORBA::String_var s(mensaje);
} // OK. ~String_var libera solo su copia interna
13
AGB
Otro:
14
Mapeo del IDL en lenguaje C++
(strings)
■
CORBA::String_var destino;
destino = CORBA::string_dup(“Hola”); // destino toma propiedad
CORBA::String_var origen;
origen = CORBA::String_dup(“Mundo”); // origen toma propiedad
destino = origen; // libera “Hola” y toma propiedad (deep copy) de “Mundo”
■
Otro ejemplo:
{
Mapeo del IDL en lenguaje C++
(strings)
■
Ejemplo:
Los ejemplos anteriores funcionan bien si el compilador es ANSI
C++ estricto. En caso contrario, se pueden evitar “core dumps”
de tres maneras distintas:
CORBA::String_var s1((const char *)”Hola”); // BIEN, pero poco elegante
CORBA::String_var s2 = CORBA::string_dup(“Hola”); // BIEN
const char *p = “Hola”;
CORBA::String_var s3;
s3 = p;
// BIEN
Si el compilador no es ANSI estricto, suele tomar “Hola” por
char * (en vez de const char *), con lo cual String_var toma
propiedad y al finalizar tratará de liberar un string estático:
CORBA::String_var s1(“Hola”); // MAL si el compilador no es ANSI
CORBA::String_var s2 = “Hola”; // MAL si el compilador no es ANSI
CORBA::String_var s3;
s3 = “Hola”; // MAL si el compilador no es ANSI
AGB
15
AGB
Mapeo del IDL en lenguaje C++
(strings)
■
Se pueden asignar String_var a punteros, pero con cuidado:
AGB
Mapeo del IDL en lenguaje C++
(strings)
■
CORBA::String_var s1 = CORBA::string_dup(“Hola”);
const char *p1 = s1; // OK. p1 apunta al string interior de s1
char *p2;
{
CORBA::String_var s2 = CORBA::string_dup(“Mundo”);
p2 = s2; // Shallow copy
s1 = s2; // Libera “Hola”, hace deep copy a “Mundo”
}
cout << p1;
// MAL: p1 apunta al vacío
cout << p2;
// MAL: p2 apunta al vacío
16
Como se debe pasar un string como parámetro de entrada a
una función:
void print_string(const char *s) // Se debe pasar como const char *
{
cout << s << endl;
}
int main()
{
CORBA::String_var msj = CORBA::string_dup(“Hola”);
print_string(msj);
// BIEN
print_string(“Mundo”); // BIEN
}
17
AGB
18
Mapeo del IDL en lenguaje C++
(strings)
■
String como parámetro de entrada-salida de una función:
Mapeo del IDL en lenguaje C++
(strings)
■
void cambiar_string(const char *&s) // Se debe pasar como const char *&
{
// para que pueda apuntar a un nuevo espacio de memoria
CORBA::string_free(s);
s = CORBA::string_dup(“Nuevo string”);
}
int main()
{
CORBA::String_var msj = CORBA::string_dup(“Hola”);
cambiar_string(msj);
// BIEN
cout << msj;
// BIEN
char *p = CORBA::string_dup(“Hola”); // Prohibido usar new
cambiar_string(p);
// BIEN
cout << p;
// BIEN
CORBA::string_free(p);
// Obligatorio
}
AGB
CORBA::String_var s(CORBA::string_dup(“Hola”);
print_string(s);
// Puede fallar en compiladores no ANSI
print_string(s.in());
// Funciona con cualquier compilador
cambiar_string(s);
// Puede fallar en compiladores no ANSI
cambiar_string(s.inout());
// Funciona con cualquier compilador
19
AGB
Mapeo del IDL en lenguaje C++
(strings)
■
El paso de string a una función podría fallar si el compilador no
es ANSI C++ estricto. Para evitarlo, la clase String tiene varias
funciones de ayuda (in, out, inout, _retn):
out() es ligeramente distinto a inout(), ya que primero libera la
memoria antes de entrar a la función. Por ejemplo:
20
Mapeo del IDL en lenguaje C++
(strings)
■
void leer_string(char * &s)
{
s = CORBA::string_dup(...); // Lee una línea de texto de algún sitio
}
_retn() se usa para retornar un string cediendo su propiedad.
Por ejemplo:
for(int i = 0 i < num_lineas; i++)
{
CORBA::String_var linea = get_line(); // Lee una linea de un archivo
cout << linea;
} // El destructor de linea libera el string
Funciona con:
Siendo la función:
CORBA::String_var linea;
leer_string(linea.out()); // La primera línea se lee y se ignora
leer_string(linea.out()); // Libera la primera línea y lee la segunda
char * get_line()
{
CORBA::String_var s = CORBA::string_dup(...); // Lee string de archivo
if(error())
// Si se lanza una excepción, las variables locales se
throw Exception(); // destruyen (“s” libera la memoria de su string)
return s._retn();
// Aquí “s” cede la propiedad de su string
}
21
AGB
Mapeo del IDL en lenguaje C++
(strings)
■
Si hay strings dentro de otro tipo mas complejo (estructuras,
secuencias, excepciones y arrays), entonces se mapea a
String_mgr, que es idéntico a String_var, excepto que el
constructor por defecto crea un string de longitud cero (en vez
de inicializarlo como puntero nulo).
PUNTERO NULO
p
■
■
■
AGB
23
Los números fixed se mapean en la clase Fixed de C++, que
contiene muchos constructores. Ejemplo:
Fixed
Fixed
Fixed
Fixed
Fixed
Fixed
Fixed
Fixed
Fixed
0
Ello facilita las cosas al programador (no necesita inicializar los
strings internos). Recordar que está prohibido pasar punteros
nulos a través de una interfase IDL.
El tipo String_mgr es para uso interno. No debe usarse
directamente por el programador.
22
Mapeo del IDL en lenguaje C++
(Fixed)
PUNTERO A STRING VACÍO
q
0
AGB
■
a; // Constructor por defecto (1 dígito entero, 0 dígitos decimales)
b = 45; // Equivale al tipo IDL fixed<2,0>
c = 21.0; // Equivale al tipo IDL fixed<2,0>
d = 21.3; // Equivale al tipo IDL fixed<3,1>
e = 0.1; // Equivale al tipo IDL fixed<2,1> pero podría ser fixed<18,17>
f = 1E30; // Equivale al tipo IDL fixed<31,0>
g = 1E32; // Excepción DATA_CONVERSION
h = “-123.45”; // Equivale al tipo IDL fixed<5,2>
c = “0.1”; // Equivale al tipo IDL fixed<2,0>. Aquí no hay error de redondeo
La clase Fixed proporciona además sobrecarga para todas las
operaciones aritméticas (+, -, *, /, ++, --, =, +=, etc.), de
comparación (>,<,>=,<=,==,!=) y de entrada-salida en flujos
(<<,>>).
AGB
24
Mapeo del IDL en lenguaje C++
(Estructuras)
■
Si la estructura contiene únicamente tipos de longitud fija, se
comporta como cabe esperar:
struct Dato
{
double x;
long y;
};
■
Mapeo del IDL en lenguaje C++
(Estructuras)
■
// IDL
struct Persona
// IDL
{
string nombre;
long edad;
};
Se convierte en:
■
struct Dato
// C++
{
CORBA::Double x;
CORBA::Long y;
// Otras funciones miembro, para uso interno de CORBA
};
AGB
25
AGB
Uso estático:
■
Persona jefe, empleado;
jefe.nombre = CORBA::string_dup(“Jose”);
jefe.edad = 40;
empleado.nombre = CORBA::string_dup(“Pepe”);
empleado.edad = 25;
jefe = empleado; // Copia profunda (deep copy)
} // Aquí se destruye jefe y empleado y automáticamente también se destruyen
// sus campos nombre
AGB
Se usa así:
{
// C++
const char * colores[] = { “blanco”, “rojo”, “azul”, “amarillo” };
Mezcla mezcla;
mezcla.length(4); // Crea una secuencia de 4 strings vacíos (“” “” “” “”)
for(CORBA::Ulong i = 0; i < mezcla.length(); i++)
mezcla[i] = colores[i];
mezcla[2] = CORBA::string_dup(“verde”); // primero libera “azul”
mezcla.length(6); // Hace crecer la secuencia a 6 (añade 2 strings vacíos)
mezcla[4] = CORBA::string_dup(“verde”);
mezcla[5] = CORBA::string_dup(“gris”);
mezcla.length(3); // Trunca la secuencia a 3 (libera “amarillo”, “verde” y “gris”)
} // La secuencia se destruye liberando sus elementos “blanco”, “rojo” y “verde”
27
AGB
Mapeo del IDL en lenguaje C++
(Secuencias ilimitadas)
■
Ejemplo con manejo dinámico de memoria:
■
Genera en C++:
// C++
28
Mapeo del IDL en lenguaje C++
(Secuencias ilimitadas)
typedef sequence<string> Mezcla; // IDL
class Mezcla { ... };
Las secuencias son mas complejas, pues tienen mas funciones
miembro de ayuda (veremos solo las mas relevantes). Ejemplo:
typedef sequence<string> Mezcla; // IDL ==> genera en C++ ==> class Mezcla;
Uso dinámico:
Persona *jefe = new Persona;
jefe->nombre = CORBA::string_dup(“Jose”);
jefe->edad = 40;
//...
delete jefe; // Automáticamente se destruye el campo nombre
26
Mapeo del IDL en lenguaje C++
(Secuencias ilimitadas)
{
■
Se convierte en:
struct Persona
// C++
{
CORBA::String_mgr nombre; // Se inicializa automáticamente a “”
CORBA::Long edad;
// Otras funciones miembro, para uso interno de CORBA
};
Mapeo del IDL en lenguaje C++
(Estructuras)
■
Si la estructura contiene también datos de longitud variable, se
inicializan automáticamente evitando punteros nulos, y se
destruyen también automáticamente:
■
Y se usa así:
Resumiendo, se puede aumentar o disminuir el tamaño de la
secuencia, así como averiguar su longitud, con la función
miembro length().
Existen otros constructores:
Mezcla mezcla(6); // Crea una secuencia de 6 strings
const char * colores[] = { “blanco”, “rojo”, “azul”, “amarillo” };
Mezcla * mezcla = new Mezcla;
mezcla->length(4); // Crea una secuencia de 4 strings vacíos (“” “” “” “”)
for(CORBA::Ulong i = 0; i < mezcla->length(); i++)
(*mezcla)[i] = colores[i];
// ...
delete mezcla; // Libera todos los strings internos
AGB
■
■
29
Los elementos de una secuencia no tienen por qué estar
contiguos en memoria.
La inserción (o truncamiento) de nuevos elementos se hace
siempre por el final.
AGB
30
Mapeo del IDL en lenguaje C++
(Secuencias limitadas)
■
Las secuencias limitadas son similares a las ilimitadas, pero hay
que especificar el número máximo de elementos:
Mapeo del IDL en lenguaje C++
(Arrays)
■
typedef float Valores[4];
// IDL
struct Alumno
{
string nombre;
float nota;
};
typedef Alumno Estudiante[45];
typedef sequence <string, 45> Estudiantes;
■
■
Hay que usar siempre typedef en el IDL para definir arrays:
Con la función length() se puede acortar o alargar la secuencia,
pero siempre sin sobrepasar ese número máximo.
El comportamiento es indefinido si se intenta aumentar ese
número máximo (posible core dump).
■
Y luego se pueden usar así (uso normal y corriente):
Valores x = { 1.0, 4.8, -3.2, 0.001 };
// C++
x[0] = x[2];
Estudiante asignatura;
asignatura[0].nombre = CORBA::string_dup(“Luisa”);
asignatura[0].nota = 3.8;
AGB
31
AGB
Mapeo del IDL en lenguaje C++
(Arrays)
■
Si se desean manejar los arrays dinámicamente no se debe
usar new y delete sino Nombre_slice, Nombre_alloc(),
Nombre_free(), Nombre_dup() y Nombre_copy():
AGB
Mapeo del IDL en lenguaje C++
(Uniones)
■
■
Valores_slice *p = Valores_alloc(4); // Pide memoria. Si no hay retorna null
p[3] = -0.1;
Valores_slice *q = Valores_dup(p); // Copia
Valores x;
// Estático
Valores_copy(&x, p); // Copia profunda para arrays estáticos y/o dinámicos
Valores_free(p); // Libera memoria
Valores_free(q); // Libera memoria
■
■
Ejemplo:
union U switch(char)
{
case ‘L’:
long numero;
case ‘c’:
case ‘C’:
char letra;
default:
string mensaje;
};
Las uniones IDL no se mapean a uniones C++ debido a que
son discriminadas. Se mapean en clases de C++.
No hay garantías de que todos los miembros de la unión se
mapeen en el mismo lugar de memoria. Cada ORB podría
hacerlo a su manera. De modo que una union CORBA no sirve
para hacer conversión de tipos, como en C o C++.
De todos modos, solo es lícito acceder a un miembro, si su
discriminante lo indica como activo.
Para acceder al discriminante se usa la función miembro _d()
33
AGB
Mapeo del IDL en lenguaje C++
(Uniones)
■
34
Mapeo del IDL en lenguaje C++
(Uniones)
■
// IDL
32
Uso:
U z; // La unión z no está inicializada
z.numero = 47; // Activa numero
if(z._d() == ‘L’)
// Verifica discriminante a ver si está activo numero
cout<<z.numero(); // Imprime numero
z.letra(‘H’); // Activa letra, pero el discriminante puede ser ‘c’ o ‘C’
z._d(‘C’);
// Impone que sea ‘C’
z._d(‘L’);
// Ilegal. No se puede cambiar el discriminante si ello activa o
// desactiva miembros.
z.mensaje(CORBA::string_dup(“Hola”)); // El discriminante no queda bien definido,
// por tratarse del miembro default
AGB
35
AGB
36
Mapeo del IDL en lenguaje C++
(Operaciones)
■
Ejemplo:
■
interface Banco // IDL
{
void depositar(in unsigned long cantidad);
unsigned long balance();
};
■
Mapeo del IDL en lenguaje C++
(Operaciones)
Banco_ptr banco = ... ; // Obtiene una referencia a Banco
banco->depositar(100);
cout << banco->balance();
CORBA::release(banco);
■
Genera:
37
AGB
AGB
Mapeo del IDL en lenguaje C++
(Atributos)
Ejemplo:
■
■
entrada (in)
salida (out)
entrada-salida (inout)
retorno
Y a su vez hay dos formatos para hacer el paso de parámetros:
39
AGB
AGB
Mapeo del IDL en lenguaje C++
(Paso de parámetros)
A bajo nivel es así:
IDL
simple
enum
fixed
string
wstring
any
objref
sequence
struct,fijo
union,fijo
array,fijo
struct,variable
union,variable
array,variable
de
de
de
de
– A bajo nivel (cada tipo de parámetro para cada forma es distinto)
– Usando las clases _var (homogeneización: el paso de parámetros
es igual para todos los tipos)
class A // C++
{
public:
virtual CORBA::Short B() = 0;
virtual void B(CORBA::Short) = 0;
virtual CORBA::Char C() = 0;
};
■
Los parámetros se pueden pasar de 4 formas:
–
–
–
–
Se convierte a:
38
Mapeo del IDL en lenguaje C++
(Paso de parámetros)
interface A // IDL
{
attibute short B;
readonly attribute char C;
};
■
O bien:
Banco_var banco = ... ; // Obtiene una referencia a Banco
banco->depositar(100);
cout << banco->balance();
class Banco // C++
{
public:
virtual void depositar(CORBA::Ulong cantidad) = 0;
virtual CORBA::ULong balance() = 0;
// ...
};
■
Y se usa así:
in
inout
simple
simple &
enum
enum &
const Fixed &
Fixed &
const char *
char * &
const WChar *
WChar * &
const Any &
Any &
objref_ptr
objref_ptr &
const sequence & sequence &
const struct &
struct &
const union &
union &
const array
array_slice *
const struct &
struct &
const union &
union &
const array
array_slice *
AGB
out
simple &
enum &
Fixed &
char * &
WChar * &
Any * &
objref_ptr &
sequence * &
struct &
union &
array_slice *
struct * &
union * &
array_slice * &
return
simple
enum
Fixed
char *
WChar *
Any *
objref_ptr
sequence *
struct
union
array_slice *
struct *
union *
array_slice *
41
40
Mapeo del IDL en lenguaje C++
(Paso de parámetros)
■
Usando clases _var es así:
IDL
string
wstring
any
objref
sequence
struct
union
array
■
in
const
const
const
const
const
const
const
const
String_var &
WString_var &
Any_var &
objref_var &
sequence_var &
struct_var &
union_var &
array_var &
inout/out
String_var &
WString_var &
Any_var &
objref_var &
sequence_var &
struct_var &
union_var &
array_var &
return
String_var
WString_var
Any_var
objref_var
sequence_var
struct_var
union_var
array_var
Para los tipos simples, las enumeraciones y los fixed no se
generan clases _var. Se manejan como en la tabla anterior que,
para ellos, es homogénea a este nuevo formato.
AGB
42
Mapeo del IDL en lenguaje C++
(Paso de parámetros)
■
■
La mejor táctica es usar tipos _var, con lo cual es casi
imposible que haya “memory leaks”.
Sin embargo, hay que tener cuidado con una situación: si la
función remota retorna un parámetro variable, siempre hay que
asignarlo. Ejemplo:
interface Foo // IDL
{
string get(in long valor);
};
■
Y se usa:
obj->get(7);
// Error: memory leak
String_var s = obj->get(7); // OK
AGB
43
Descargar