Está en la página 1de 14

c cc

c 

  
TERCERA ENTREGA

Bienvenidos a la tercera entrega del curso de CORBA. Tras cubrir en las dos primeras
aspectos teóricos de CORBA vamos a afrontar en esta nueva entrega el desarrollo de
una aplicación sencilla utilizando CORBA.

Una vez cubierto este primer ejemplo y mostrados los detalles fundamentales del
desarrollo con CORBA, inicialmente utilizando el lenguaje Java en cliente y servidor,
pasaremos a enfrentarnos a la aplicación que ha sido analizada en la anterior entrega y
que básicamente consiste en implementar un sistema de comunicación para la intranet
de una empresa.


En esta entrega es necesario que el lector tenga instalado el JDK (Java Development
Kit) en su versión 1.1, a ser posible la versión 1.1.7, y debe de tener la implementación
de CORBA para Java "JavaORB", ya que fundamentalmente lo que vamos a realizar es
tomar un ejemplo de esta herramienta y analizarlo con detenimiento.

El JDK 1.1.7 para GNU/Linux el lector lo puede obtener de http://www.blackdown.org,


el grupo que mantiene Java en la plataforma GNU/Linux y que ya ha logrado portar la
versión JDK 1.2 a GNU/Linux.

La implementación de CORBA 2.2 JavaORB se puede obtener de


http://www.multimania.com/dogweb. Tuvimos algunos problemas para bajar esta
herramienta de este web así que recomendamos al lector paciencia para obtenerla.

La instalación de JDK 1.1.x a partir del "tar.gz" obtenida de "blackdown" es muy


sencilla, consistiendo básicamente en poner en el "PATH" el directorio de los binarios
de JDK.

La instalación de "JavaORB" también es muy rápida. Basta con descomprimir el ".zip"


mediante la orden "unzip <fichero>.zip" se creará un directorio donde estará todo el
"JavaORB". Con añadir a la variable de entorno "CLASSPATH" el fichero
"JavaORBv1_2.jar y al "PATH" el directorio "bin" de JavaORB todo debería de
funcionar correctamente. Se puede utilizar JavaORB con JDK 1.2 pero requiere ciertas
modificaciones que complican la instalación. El lector interesado puede encontrar dicha
documentación dentro del propio "JavaORB" en el fichero "README".

Recordamos al lector que en la anterior entrega se describía con detalle la instalación de


estos dos paquetes.

  
Como ya hemos ido repitiendo a lo largo del curso, el primer paso en todo desarrollo
CORBA es llegar a la definición de las interfaces IDL de todos los componentes del
sistema.

En nuestro ejemplo el sistema es muy sencillo. Vamos a tener un servidor CORBA que
va a actuar como una calculadora. A este servidor accederán los clientes y le pedirán
que ejecute operaciones, en concreto las operaciones de "suma" y "division".

El ejemplo se ve complementado con la demostración del uso de excepciones dentro de


un sistema CORBA, y de un servicio CORBA fundamental: el servicio de nombres.

A continuación pasamos a mostrar la IDL que vamos a seguir:

 
   
  
   
      
 


    

 


  !
 "!
#!


    $%    




   &
  '   ( )   (" *!

   
  '   ( )   (" *
 ' 
 *!
#!

Después de la anterior entrega esperamos que el lector no tenga ningún problema en


seguir está descripción IDL. En ella hay un sólo interfaz, el "Calculator" con dos
operacion muy sencillas de suma y division.

Quizás la parte más "original" sea el uso de la excepción "DivisionPorCero" que lanzará
el servidor en el caso de que el cliente intente realizar un división por cero. Esta
excepción del servidor se propagará hasta el cliente a través de CORBA.

Lo mejor para continuar con el ejemplo es que nos creemos un directorio donde ir
guardando los diferentes ficheros. A partir de ahora suponemos que dicho directorio es
"Ejemplo".

Guardamos dentro de este directorio la interfaz IDL con el nombre "Calculator.idl".


îa contamos en la anterior entrega como se pasaba esta interfaz IDL a los "cabos" y
"esqueletos" Java. Esto se lograba gracias al compilador de JavaORB "idl2java" que se
encuentra dentro del directorio "bin" de "JavaORB" y que el lector debería de tener ya
en el PATH de su entorno.

La orden a ejecutar dentro del directorio "Ejemplo" es :

 "
+ 

Tras ello se nos creará un directorio "corba_pkg" donde se van a almacenar todas las
clases Java que constuyen los "cabos y esqueletos" de CORBA, necesarios para que
tanto cliente como servidor se "enchufen" al ORB.

  

El código para implementar el cliente tiene dos partes claramente diferenciadas. En una
primera se realiza todo el proceso necesario para inicializar CORBA y contactar con el
objeto servidor CORBA a través de un servidor de nombres. En una segunda fase se
pasa a utilizar este objeto CORBA como si fuera un objeto local al cliente, momento en
el que veremos la auténtica potencia de CORBA. A continuación presentamos el código
fuente del cliente:

 
    
 
 


 ,   ' "*

( 


(   ' &- -./ *

 +
 $% 
-+-+
+ (  -+-+
+ +'-)*!

 "+
 0%  1-&
-+-+
+ ( (  !
-+-+
1 -+1-
 -  !
2

(  (+33'41-&4*!
- 
-+-+
1-+1-
5+6'(*!
#
7 ' -+-+
+ 8-+$ 1  *

&2++'41  7    ( 
1-&4*!
&2+'9*!
#
 :+

  (  (

-+-+
1-+1
 ./   6
-+-+
1-+1
. /!
.9/  6 -+-+
1-+1
'*!
.9/+  4
4!
.9/+8  44!

 ;+
 0%     (

   1-&
2

(  -+'*!
#
7 ' -+-+
1-+1-
8-+1<  *

&2++'4 (     
1-&4*!
&2+'9*!
#
7 ' -+-+
1- +1-
8-+
  *

&2++'41  7    4*!
&2+'9*!
#
7 ' -+-+
1-+1-
8-+$ 1  *

&2++'41(   4*!
&2+'9*!
#

 =+
 16     (

  
5+6'(*!
 >+
 %  (
    
2

&2++'4= ? :  4 ? + '=):* *!

&2++'4=  9  4 ? + '=)9* *!


#
7 ' 
  *

&2++'4$    @ 
4*!
&2++'40   4?+ ?4 
4?+"*!
#
7 ' -+-+
+&2  *

&2++'4$   

&24*!
&2++'+-A-'**!
#

#
#
En el primer paso del ejemplo lo que se hace es inicializar el ORB para indicarle que
vamos a utilizarle. En este momento se le pueden pasar parámetros al ORB de
inicialización como la localización del servidor de nombres, qué puerto debe de utilizar
el ORB etc. En nuestro caso no vamos a utilizar esta via de configuracion del ORB.

Una vez inicializado el ORB lo siguiente que hacemos es contactar con el servidor de
nombres. No es indispnesable tener un servidor de nombres CORBA disponible para la
aplicación, pero si suele ser muy útil su uso para centralizar todas las referencias a
objetos dentro de un servicio común. Por ello mostramos su uso en este ejemplo ya que
en cualquier uso de CORBA real, el servidor de nombres suele ser indispensable.

JavaORB trae en la herramienta un servidor de nombres. Para arrancarlo basta con ir al


direcotrio "bin" de JavaORB y ejecutar "sh naming". Recordar al lector que dentro de la
variable CLASSPATH debe estar la libreria "JavaORBv1_2_4.jar".

Una vez arrancando el servidor de nombres con la configuración estandar el ORB de


JavaORB sabe localizarlo. Para obtener una referencia a dicha objeto utilizamos el
método de la API del ORB "resolve_initial_references("NamingService")". En este caso
utilizamos esta función para obtener una referencia al servicio de nombres, pero
también se utiliza este método para obtener otros objetos del ORB como el adaptador de
objetos. Este método nos devuelve un objeto CORBA genérico, pero en realidad
nosotros sabemos que es un servidor de nombres (NamingContext) por lo que
utilizamos la función "narrow()" del objeto "Helper" del servidor de nombres para
transformar de forma segura este objeto genérico CORBA en un servidor de nombres.

Este procedimiento narrow() lo vamos a utilizar de forma constante.Cada objeto


CORBA tiene definido una clase de ayuda "Helper" con esta función, que permite
comprobar si un objeto genérico CORBA es realmente de su clase.

A lo largo del ejemplo se capturan muchas excepciones que pueden ocurrir a la hora de
interactuar con CORBA. Es mucho más seguro programar de esta forma ya que en todo
momento podemos estra informados de lo que ha podido ocurrir, siendo nuestro código
mucho más robusto.

Una vez que tenemos dentro de "naming" la referencia al objeto CORBA del servidor
de nombres, lo que hacemos en el paso 3 es construir el nombre que tiene el objeto
CORBA Calculator dentro del servidor de nombres. Este nombre lo habrá puesto allí
anteriormente el servidor CORBA que arranque dicho objeto CORBA. Los nombres
dentro del servidor de nombres tienen dos campos, un identificador y una clase. De esta
forma es más sencillo agrupar a los objetos comunes dentro de una clase.

En el paso 4 es donde realmente se contacta con el servidor de nombres y a través del


método "resolve()" obtenemos la referencia al objeto CORBA Calculator. De nuevo en
esta llamada se capturan varias excepciones. Hay que recordar al lector que esta llamada
ya va a viajar por CORBA a través de los ORB del cliente y del servidor de nombres,
ORBs que pueden estar separados por Internet p.e. por lo que pueden ocurrir muchas
incidencias en esta llamada. Aunque para nosotros como desarrolladores el trabajo de
invocar la función sea como la llamada sobre una función de un objeto local, el proceso
es mucho más complejo.
De nuevo tenemos que utilizar la función "narrow()" en el paso 5, pero en este caso
utilizando el "Helper" de Calculator, ya que es esta clase la que sabe si un objeto
genérico CORBA es o no es un objeto Calculator. En el caso de lo que sea devuelve el
objeto CORBA, pero ya como un Calculator. î una vez que tenemos este objeto
CORBA lo podemos utilizar exactamente igual que si fuera un objeto local, tal y como
podemos ver en el paso 6 en las operaciones "calc.add(5,3)" y "calc.div(5,0)". Lo más
interesante de este paso es como una excepción que se genera en el objeto remoto
CORBA viaja a través de los ORBs y es entregada al cliente. De esta forma el uso de
excepciones dentro de CORBA también es transparente para el desarrollador. En este
caso la excepción capturada es la de "DivisionPorCero" que recordamos al lector que
definimos dentro de la interfaz IDL Calculator.
En el siguiente esquema el lector puede observar la arquitectura del ejemplo y los pasos
dados para contactar con el objeto servidor:

Figura 1: Cliente CORBA



! c 

Lo primero es recomendar al lector que sea un poco paciente al enfrentarse por primera
vez al código de un servidor de CORBA. Este código i i 
  en
todos los casos, por lo que su comprensión una vez permite trabajar con CORBA con
mucha soltura en sucesivos desarrollos de servidores CORBA.

El servidor CORBA es el programa que se encarga de crear el objeto CORBA y


registrarlo dentro del ORB.

Como vamos a ver gran parte del código de este servidor es idéntico al del cliente, en
especial las partes de inicialización del ORB y de uso del servidor de nombres. Sin
embargo dentro del servidor CORBA vamos a ver un elemento que no aparecía en el
cliente:   " . Recordar al lector que el adaptador de objetos es el
que mantiene control sobre los objetos que están registrados del ORB y el se encarga de
encaminar las peticiones de los clientes hacia los objetos CORBA, entre otras
funciones.

Como ya comentamos en entregas anteriores CORBA 2.2 introdujo la gran novedad del
POA (Adaptador de Objetos Portable), que sustituyó al BOA (Adaptador de Objetos
Báscio) que tenía muchos problemas a la hora de portar aplicaciones entre diferentes
ORB en el lado del servidor.

Nos vamos a centrar en este ejemplo en POA al haber quedado BOA obsoleto a partir
de CORBA 2.2, ha desaparecido del estandar. POA es un adaptador de objetos cuyo uso
puede ser muy sencillo pero que ofrece muchas posibilidades de diseño de la aplicación
CORBA, puediendo llegar a soportar diseños muy complejos. Quizás en alguna futura
entrega del curso se cubra POA en profundidad en un artículo dedicado a él.

Pasamos pues a ver el código del servidor CORBA, dentro del cúal se crea el objeto
CORBA "Calculator" y se da de alta en el ORB. A parir de ese momento cualquier
cliente podrá acceder al objeto CORBA.

 
     
   
 

 &    

(  & 



(   ' &- -./ *

 +
 $% 
-+-+
+ (  -+-+
+ +'-) *!

 "+
      
-+-+
+ ( (  !
-+-+(&+     !
2

(  (+33'4  4*!
#
7 ' -+-+
+ 8- +$ 1  *
#

 :+
 5  6    ( 
  
   -+-+(&+ 5+6'(*!

 ;+
 $  (


 $   6
 $'*!

2

 =+
     
(2./ $   +3('*!

 >+
 (    
-+-+
+ (    + 33'$ *!

 >+
    1-&
-+-+
+ ( (  !
-+-+
1-+1-
 -  !
2

(  (+3 3'41-&4*!
&2++'40%   1-&4*!
-  -+-+
1-+1-
5+6'(*!
&2++'416  1-&4*!
#
7 ' -+-+
+ 8-+$ 1  *

&2++'41  7    ( 
1-&4*!
&2+'9*!
#

 ' -   *



&2++'41  7     1-&4*!
&2+'9*!
#

 B+

  (  (

-+-+
1-+1
 ./   6
-+-+
1-+1
. /!
.9/  6 -+-+
1-+1
'*!
.9/+  4
4!
.9/+8  44!

2

-+( ')*!
#
7 ' -+-+
1-+1-
8-+1<  *

&2++'4 (   4*!
&2+'9*!
#
7 ' -+-+
1-+1-
8-+ 2   *

&2++'4C 72  (   (4*!
-+( '*!
&2+'9*!
#
7 ' -+-+
1-+1-
8-+$ 1  *

&2++'41( D 4*!
&2+'9*!
#
7 ' -+-+
1-+1-
8-+
  
*

&2++'41  7    4*!
&2+'9*!
#

 E+
   -     
 +73 A-'*+'*!
&2++'4   D  +++4*!
 F+
 1 G       (

(+'*!
#
7 ' +-+  *

&2++'4& 7    @ 4*!
+&8,'*!
#

#
#

El paso 1 es idéntico al del cliente. Se inicializa el ORB. En el paso 2 ya empezamos a


trabajar con POA. El adapator de objetos POA siempre tiene un POA raíz llamado
"RootPOA" y que el ORB conoce. Los objetos dentro del ORB se registran dentro de un
POA determinado, pudiendo cada POA tener políticas de gestión de dichos objetos
diferentes. Dentro del ORB pueden existir varios POAs organizados en una estructura
jerárquica en árbol.

En el caso más sencillo utilizamos sólo el "RootPOA", que tiene unas políticas de
gestión predefinidas, y en él registramos a todos nuestros objetos. Si nuestra
arquitectura es más compleja habrá que utilizar diferentes POAs con características
diferentes, aunque la programación de dichos servidores se complica bastante más que
cuando sólo utilizamos un único POA.

En la figura 2 podemos observar el POA de nuestra aplicación y un ejemplo de como


podría ser una arquitectura de POAs más complejo
|
i |:|it t||
 ||

|l |t t | |l| || t  |l| i|l| jt |"R t


"|i ||l|
 i |" l i itil  "|l|
RB |C  | t| i | |l| |
jt |C
RB| i | |l| || || | t| jt || | i|l|
|
|i |l|"  "|l|
l|

 |l| || | | |l| jt |C


RB|Cllt 
||il ti |
| t| jt |l| | |l| ii t|t | |!|l t || |!|
 ill| |ti l í|
||l|il ti || |i t"|#$ || |l ||
%|Cllt 
|il t  |l|i t"|Cllt  | |l| |  |
"  t"| |  t | |"Cllt 
"| | |  t|

 |l| |&|i t | t|"  t"| t |l|"R t


"|i ||l| i |
"tit jt"||l| #||
|

l|ti|  t | jt | t |l|


|l|
RB|l| i  |i| |i tii |
| |l|i%| i |!|l  | |"  t#"| |l| |'|
t   | t|i tii | | | i|| jt | |l|i |i  i |
i t|| t|  | |l| jti ||i t i| t| i|l| jt | t |l|
i ||  |

 | ii t||t  ||%| |i t| t| i|l| jt |Cllt |


 t |l| i ||  |!|| |llí|| |||i|l|li t|| |l|
 i|l| jt |

|ll | |l| |(| ||l| i ||  | |i ti |l||l|li t|l|
 |)| |ti |i ti |l||l|li t | |l|*i |||í| |"||
jt|" l"| |l| i ||  |jt |"i " | |i |i|
 i | t |l| i ||  |l| i|l| jt |"Cllt "| |l|
|"Cllt " "*l"|
En el paso 9 activamos el "Manager" del RootPOA. Este manager es el que se encarga
de recibir las peticiones sobre los objetos registrados en este POA y distribuirlas al
"servant" adecuado, es decir, enviarla a la implementación de la interfaz IDL adecuada.
En nuestro caso si se recibe una invocación para Calculator, el manager se la enviaría a
CalculatorImpl.

Por último en el paso 10 se invoca el método "orb.run()" que cede el control de la


ejecución al ORB para que puede comenzar a recibir invocaciones del cliente. De este
método solo se vuelve en el caso de que el ORB finalice, bien por salida provocada o
por muerte.

Recordar al lector que aunque le haya resultado en algun momento un poco compleja o
tediosa la lectura de este apartado, una vez entendidos estos pasos son siempre igual en
cualquier servidor CORBA, independientemente del lenguaje que se utilice y de lo
complejo de la aplicación. La única parte que se complicaría algo más sería la de
creación de POAs y sus políticas asociadas. Todo lo demás es idéntico siempre.

En la figura 3 podemos observar el momento en el que se registra el objeto CORBA


CalculatorImpl dentro del adaptador de objetos del ORB, momento a partir del cual es
conocido dentro de CORBA y puede ser accedido por cualquier cliente remoto.
Figura 3: Registro de objeto CORBA

#c$ 

Bueno, ya hemos alcanzado la parte fácil. La implementación de la interfaz IDL es tan


sencilla como implementar una interfaz que no fuera CORBA. Aquí va el código:

 
   

 

 $ %   

( 
$  
 

HH
H @ 

(   ' ( )  ("*

&2++'4&  4?( ?4 ? 4?("*!
 ( ? ("!
#

HH
H @ 

(  ' ( )  ("*
76  2I

&2++'4  4?( ?4  4?("*!

 ' ("  9 *
76 6 
'( )("*!

 (  ("!
#
#

De este implementación lo único que hay que destacar es que el objeto "CalculatorImpl"
hereda del objeto "CalculatorPOA". Esto lo que provoca es que a "CalculatorImpl" se le
añada todo el "skeleton" (esqueleto) utilizando herencia lo que permite que sea accedido
el objeto a través de CORBA. Recordemos que este esqueleto se generaba de forma
automática de la interfaz OMG/IDL utilizando el compilador "java2idl".

Para nosotros como desarrolladores nos vale con saber que debemos de heredar de
"CalculatorPOA" para que nuestro objeto pueda ser accedido por CORBA. Nos
podemos olvidar de que existe CORBA a partir de ese momento y trabajar como si todo
el sistema fuera local. De hecho, se puede tener un especialista en CORBA dentro del
proyecto y que todos los demas desarrolladores no sepan que por debajo se está
utilizando CORBA.

  

Si quisieramos completar la interfaz de nuestra calculadora y añadir las operaciones de


resta y multiplicación sería muy sencillo.

1.| Lo primero que haríamos sería editar el fichero IDL "Calculator.idl" y añadir
dentro de las llaves de "interface Calculator {..}" :
"+|   '   ( )   (" *!
  '   ( )   (" *!

Como ninguna de las dos levanta excepciones no hace falta utilizarlas.

3.| Una vez hecho esto volvemos a pasar el compilador "idl2java" para regenerar
los cabos y esqueletos.
4.| Por último basta con implementar estas dos operaciones dentro de
CalculatorImpl y ya podrían ser utilizadas por cualquier cliente CORBA.
Vemos con que facilidad se pueden ampliar las interfaces IDL, y vemos que estos
cambios no afectan para nada al servidor de CORBA. î el cliente CORBA solo se ve
afectado en el caso de que se elimine alguna operación de la interfaz que el utilice.

Esta facilidad para ampliar las interfaces y el hecho de que los implementadores de las
interfaces de IDL no tenga porque saber nada de CORBA son dos características
fundamentales de CORBA.

c $   

Como conclusión de este desarrollo CORBA podemos destacar los siguientes puntos de
la arquitectura CORBA.

¢| Facilidad de implementación de las interfaces


¢| Código específico CORBA muy parecido siempre
¢| Facilidad de ampliación de funcionalidad
¢| Transparencia total respecto a la distribución (incluso excepciones)
¢| Potencial enorme: multilenguaje, multiarquitetcura, multiprotocolo

#%&
En la cuarta entrega del curso vamos a ver como la comunicación entre objetos Java y
C++ es trivial gracias a CORBA. También introduciremos algún servicio más de
CORBA como pueden ser los de transacciones y eventos. Por último veremos las
nuevas caracterticas de CORBA 2.3 y la arquitectura de componentes de CORBA 3.0.
Hasta el próximo número.

'
¢| Página del curso: http://www.angelfire.com/al/acs
¢| JavaORB: http://www.multimania.com/dogweb
¢| JDK para GNU/Linux: http://www.blackdown.org
¢| OMG: http://www.omg.org

También podría gustarte