<html>
<head><title>CURSO PRCTICO DE CORBA EN GNU/LINUX</title></head>
<body bgcolor="#ffffff">
<div align=right>Alvaro del Castillo San Flix</div>
<h1>CURSO PRCTICO DE CORBA EN GNU/LINUX</h1>
<P>
Bienvenidos a la tercera entrega del curso de CORBA. Tras cubrir en
las dos primeras aspectos tericos de CORBA vamos a afrontar
en esta nueva entrega el desarrollo de una aplicacin sencilla
utilizando CORBA.<br>
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 aplicacin que ha sido analizada en la anterior entrega y que bsicamente
consiste en implementar un sistema de comunicacin para la intranet
de una empresa.
<p>
<h2>Herramientas necesarias</h2>
<p>
En esta entrega es necesario que el lector tenga instalado 
el JDK (Java Development Kit) en su versin 1.1, a ser posible
la versin 1.1.7, y debe de tener la implementacin de CORBA
para Java "JavaORB", ya que fundamentalmente lo que vamos a
realizar es tomar un ejemplo de esta herramienta y analizarlo con
detenimiento.
<p>
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 versin JDK 1.2 a GNU/Linux.<br>
La implementacin 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.
<p>
La instalacin de JDK 1.1.x a partir del "tar.gz" obtenida de "blackdown"
es muy sencilla, consistiendo bsicamente en poner en el "PATH" el directorio
de los binarios de JDK.
<p>
La instalacin de "JavaORB" tambin es muy rpida. Basta con descomprimir
el ".zip" mediante la orden "unzip &lt;fichero&gt;.zip" se crear un
directorio donde estar todo el "JavaORB". Con aadir a 
la variable de entorno "CLASSPATH" el fichero "JavaORBv1_2.jar y al "PATH"
el directorio "bin" de JavaORB todo debera de funcionar correctamente.
Se puede utilizar JavaORB con JDK 1.2 pero requiere ciertas modificaciones que
complican la instalacin. El lector interesado puede encontrar dicha
documentacin dentro del propio "JavaORB" en el fichero "README".<br>
Recordamos al lector que en la anterior entrega se describa con detalle
la instalacin de estos dos paquetes.
<BR>
<B>La IDL del ejemplo</B><BR>
<BR>
Como ya hemos ido repitiendo a lo largo del curso, el primer paso
en todo desarrollo CORBA es llegar a la definicin de las interfaces
IDL de todos los componentes del sistema.<br>
En nuestro ejemplo el sistema es muy sencillo. Vamos a tener un servidor CORBA
que va a actuar como una calculadora. A este servidor accedern los
clientes y le pedirn que ejecute operaciones, en concreto las operaciones
de "suma" y "division".<br>
El ejemplo se ve complementado con la demostracin del uso de excepciones
dentro de un sistema CORBA, y de un servicio CORBA fundamental: el servicio 
de nombres.<br>
A continuacin pasamos a mostrar la IDL que vamos a seguir:
<pre>
// ============================================================
// = Ejemplo de CORBA de JavaORB
// = -------------------------------------------------------- =
// = Una calculadora sencilla                     =
// ============================================================

//
// Descripcion de una excepcion
//
exception DivisionPorCero
{
  float op1;
  float op2;
};

//
// Descripcion de la Interfaz de la calculadora
//
interface Calculator
{
  // operacion de Suma
  float add ( in float nb1, in float nb2 );

  // operacion de Division
  float div ( in float nb1, in float nb2 )
  raises ( DivisionPorCero );
};
</pre>

Despus de la anterior entrega esperamos que el lector no tenga ningn problema
en seguir est descripcin IDL. En ella hay un slo interfaz,
el "Calculator" con dos operacion muy sencillas de suma y division.<br>
Quizs la parte ms "original" sea el uso de la excepcin
"DivisionPorCero" que lanzar el servidor en el caso de que el
cliente intente realizar un divisin por cero. Esta excepcin
del servidor se propagar hasta el cliente a travs de CORBA.
<br>
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".<br>
Guardamos dentro de este directorio la interfaz IDL con el nombre
"Calculator.idl".<br>
Ya 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 debera de tener ya en el PATH de su entorno.<br>
La orden a ejecutar dentro del directorio "Ejemplo" es :
<pre>
idl2java Calculator.idl
</pre> 
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.
<BR>
<B>Desarrollo del cliente</B><BR>
<BR>
El cdigo 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 travs 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 autntica potencia de CORBA.
A continuacin presentamos el cdigo fuente del cliente: 
<pre>
// ============================================================
// = Ejemplo de cliente CORBA =
// ============================================================

//
// Tutorial de JavaORB (Paso 2)
//
public class Client
{
  public static void main( String args[] )
  {
    // 1.
    // Inicializacion del ORB
    org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args,null);

    // 2.
    // Localizacion del NamingService
    org.omg.CORBA.Object obj = null;
    org.omg.CosNaming.NamingContext naming = null;
    try
    {
            obj = orb.resolve_initial_references("NamingService");
            naming = org.omg.CosNaming.NamingContextHelper.narrow(obj);
    }
    catch ( org.omg.CORBA.ORBPackage.InvalidName name )
    {
            System.out.println("No se ha podido obtener el NamingService");
            System.exit(0);
    }

    // 3.
    // Construccion del nombre del objeto Calculator
    org.omg.CosNaming.NameComponent [] name = new org.omg.CosNaming.NameComponent[1];
    name[0] = new org.omg.CosNaming.NameComponent();
    name[0].id = "Calculator";
    name[0].kind = "Example";

    // 4.
    // Localizacion de la referencia al objeto Calculator 
    // dentro del NamingService
    try
    {
            obj = naming.resolve(name);
    }
    catch ( org.omg.CosNaming.NamingContextPackage.NotFound ex )
    {
            System.out.println("Objeto no encontrado en el NamingService");
            System.exit(0);
    }
    catch ( org.omg.CosNaming.NamingContextPackage.CannotProceed ex )
    {
            System.out.println("No se ha podido continuar");
            System.exit(0);
    }
    catch ( org.omg.CosNaming.NamingContextPackage.InvalidName ex )
    {
            System.out.println("Nombre invalido");
            System.exit(0);
    }

    // 5.
    // Narrow de la referencia al objeto 
    Calculator calc = CalculatorHelper.narrow(obj);
    // 6.
    // Utilizamos el objeto Calculator somo si fuera local 
    try
    {
            System.out.println("5 + 3 = " + calc.add(5,3) );

            System.out.println("5 / 0 = " + calc.div(5,0) );
    }
    catch ( DivisionPorCero ex )
    {
            System.out.println("Interceptada intento de divisn por cero");
            System.out.println("La division era "+ex.op1+" / "+ex.op2);
    }
    catch ( org.omg.CORBA.SystemException ex )
    {
            System.out.println("Interceptada una excepcion CORBA System");
            System.out.println(ex.getMessage());
    }

  }
}
</pre>
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 parmetros al ORB de
inicializacin como la localizacin 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.<br> 
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
aplicacin, pero si suele ser muy til su uso para centralizar todas las referencias
a objetos dentro de un servicio comn. Por ello mostramos su uso en este ejemplo
ya que en cualquier uso de CORBA real, el servidor de nombres suele ser indispensable.
<br>
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".
<br>
Una vez arrancando el servidor de nombres con la configuracin estandar el ORB
de JavaORB sabe localizarlo. Para obtener una referencia a dicha objeto utilizamos
el mtodo de la API del ORB "resolve_initial_references("NamingService")". En este
caso utilizamos esta funcin para obtener una referencia al servicio de nombres, pero
tambin se utiliza este mtodo para obtener otros objetos del ORB como
el adaptador de objetos. Este mtodo nos devuelve un objeto CORBA genrico, pero
en realidad nosotros sabemos que es un servidor de nombres (NamingContext) por lo
que utilizamos la funcin "narrow()" del objeto "Helper" del servidor de nombres para 
transformar de forma segura este objeto genrico CORBA en un servidor de nombres.
<br>
Este procedimiento narrow() lo vamos a utilizar de forma constante.Cada objeto CORBA
tiene definido una clase de ayuda "Helper" con esta funcin, que permite comprobar
si un objeto genrico CORBA es realmente de su clase.
<br>
A lo largo del ejemplo se capturan muchas excepciones que pueden ocurrir a la hora
de interactuar con CORBA. Es mucho ms seguro programar de esta forma ya que
en todo momento podemos estra informados de lo que ha podido ocurrir, siendo
nuestro cdigo mucho ms robusto.
<br>
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 ms sencillo agrupar a los objetos comunes dentro de una clase.
<br>
En el paso 4 es donde realmente se contacta con el servidor de nombres y a travs
del mtodo "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 travs 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 funcin sea como la llamada sobre
una funcin de un objeto local, el proceso es mucho ms complejo.
<br>
De nuevo tenemos que utilizar la funcin "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 genrico
CORBA es o no es un objeto Calculator. En el caso de lo que sea devuelve el objeto
CORBA, pero ya como un Calculator. Y 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 ms interesante
de este paso es como una excepcin que se genera en el objeto remoto CORBA viaja
a travs de los ORBs y es entregada al cliente. De esta forma el uso de excepciones dentro
de CORBA tambin es transparente para el desarrollador. En este caso la excepcin
capturada es la de "DivisionPorCero" que recordamos al lector que definimos dentro
de la interfaz IDL Calculator.
<BR>En el siguiente esquema el lector puede observar la
arquitectura del ejemplo y los pasos dados para contactar con el objeto servidor:

<img src="cliente.gif">
 
<BR>
<B>El servidor CORBA</B><BR>
<BR>
Lo primero es recomendar al lector que sea un poco paciente al enfrentarse
por primera vez al cdigo de un servidor de CORBA. Este cdigo
<em>siempre es idntico al 90%</em> en todos los casos, por lo que
su comprensin una vez permite trabajar con CORBA con mucha soltura
en sucesivos desarrollos de servidores CORBA.<br> 
El servidor CORBA es el programa que se encarga de crear el objeto CORBA y
registrarlo dentro del ORB.<br>
Como vamos a ver gran parte del cdigo de este servidor es idntico
al del cliente, en especial las partes de inicializacin del ORB
y de uso del servidor de nombres. Sin embargo dentro del servidor
CORBA vamos a ver un elemento que no apareca en el cliente: <b>el 
adaptador de objetos</b>. Recordar al lector que el adaptador de objetos
es el que mantiene control sobre los objetos que estn registrados
del ORB y el se encarga de encaminar las peticiones de los clientes
hacia los objetos CORBA, entre otras funciones.<br>
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 Bscio) que tena muchos problemas a la
hora de portar aplicaciones entre diferentes ORB en el lado del servidor.
<br>
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 diseo de la aplicacin CORBA, puediendo
llegar a soportar diseos muy complejos. Quizs en alguna
futura entrega del curso se cubra POA en profundidad en un artculo
dedicado a l.<br>
Pasamos pues a ver el cdigo del servidor CORBA, dentro del cal
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.<br>
<pre>
// ============================================================
// = Ejemplo de servidor CORBA con JavaORB                  =
// ============================================================

// Servidor con POA

public class ServerPOA
{
  public static void main( String args[] )
  {
    // 1.
    // Inicializamos el ORB
    org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args, null);

    // 2.
    // Resolvemos la referencia al RootPOA
    org.omg.CORBA.Object objPoa = null;
    org.omg.PortableServer.POA rootPOA = null;
    try
    {
      objPoa = orb.resolve_initial_references("RootPOA");
    }
    catch ( org.omg.CORBA.ORBPackage.InvalidName ex )
    {}

    // 3.
                // Hacemos un narrow de referencia de objeto a referencia POA
    rootPOA = org.omg.PortableServer.POAHelper.narrow(objPoa);

    // 4.
    // Instanciamos un objeto Calculator
    CalculatorPOAImpl calc = new CalculatorPOAImpl();

    try
    {
      // 5.
      // Activamos el servant dentro del ORB
      byte[] servantId = rootPOA.activate_object(calc);

      // 6.
      // Obtenemos la referencia al servant
      org.omg.CORBA.Object ref = rootPOA.id_to_reference(servantId);

      // 6.
      // Accedemos al NamingService
      org.omg.CORBA.Object obj = null;
      org.omg.CosNaming.NamingContext naming = null;
      try
      {
        obj = orb.resolve_initial_references("NamingService");
        System.out.println("Locallizado el NamingService");
        naming = org.omg.CosNaming.NamingContextHelper.narrow(obj);
        System.out.println("Narrow del NamingService");
      }
      catch ( org.omg.CORBA.ORBPackage.InvalidName name )
      {
        System.out.println("No se ha podido obtener el NamingService");
        System.exit(0);
      }

      if ( naming == null )
      {
        System.out.println("No se ha encontrado el NamingService");
        System.exit(0);
      }

      // 7.
      // Construccion del nombre del objeto Calculator
      org.omg.CosNaming.NameComponent [] name = new org.omg.CosNaming.NameComponent[1];
      name[0] = new org.omg.CosNaming.NameComponent();
      name[0].id = "Calculator";
      name[0].kind = "Example";

      try
      {
        naming.bind(name,ref);
      }
      catch ( org.omg.CosNaming.NamingContextPackage.NotFound ex )
      {
        System.out.println("Objeto no encontrado");
        System.exit(0);
      }
      catch ( org.omg.CosNaming.NamingContextPackage.AlreadyBound ex )
      {
        System.out.println("Ya hay un objeto con ese nombre");
        naming.unbind(name);
        System.exit(0);
      }
      catch ( org.omg.CosNaming.NamingContextPackage.InvalidName ex )
      {
        System.out.println("Nombre invlido");
        System.exit(0);
      }
      catch ( org.omg.CosNaming.NamingContextPackage.CannotProceed ex )
      {
        System.out.println("No se ha podido continuar");
        System.exit(0);
      }

      // 8.
      // Activamos el gestor de invocaciones del POA
      rootPOA.the_POAManager().activate();
      System.out.println("El servidor est preparado...");
      // 9.
      // Nos quedamos a la espera de peticiones sobre Calculator
      orb.run();
    }
    catch ( java.lang.Exception ex )
    {
      System.out.println("Se ha capturado una excepcin");
      ex.printStackTrace();
    }

  }
}
</pre>
El paso 1 es idntico 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 
raz llamado "RootPOA" y que el ORB conoce. Los objetos dentro del ORB se 
registran dentro de un POA determinado, pudiendo cada POA tener polticas 
de gestin de dichos objetos diferentes. Dentro del ORB pueden existir varios
POAs organizados en una estructura jerrquica en rbol.<br>
En el caso ms sencillo utilizamos slo el "RootPOA", que tiene unas polticas
de gestin predefinidas, y en l registramos a todos nuestros objetos.
Si nuestra arquitectura es ms compleja habr que utilizar diferentes
POAs con caractersticas diferentes, aunque la programacin de dichos
servidores se complica bastante ms que cuando slo utilizamos un nico POA.
<br>
En la figura 2 podemos observar el POA de nuestra aplicacin y un
ejemplo de como podra ser una arquitectura de POAs ms complejo 
<img src="CalculatorPOA.gif"><br>
Por lo tanto en el paso 2 obtenemos la referencia al objeto "RootPOA" gracias
a la funcin "resolve_initial_references()" del ORB. Como esta funcin
nos devuelve un objeto CORBA genrico en el paso 3  debemos de pasar este objeto a 
una referencia real a POA gracias al "narrow()" del POAHelper.<br>
En el paso 4 es donde creamos el objeto CORBA CalculatorPOA. La implementacin
de este objeto la veremos en el siguiente apartado, aunque ya adelantamos que
es muy sencilla. En terminologa POA a la implementacin de una interfaz
IDL, que es lo que hace CalculatorPOA implementando la interfaz Calculator, se 
la conoce como "servant". En nuestro caso "CalculatorPOA" es un servant.<br>
En el paso 5 registramos este "servant" dentro del "RootPOA" gracias a la
funcin "activate_object()" de la API de POA.<br>
Al activar nuestro objeto dentro del POA del ORB del servidor, recibe un 
identificador que nos devuelve dicha funcin y almacenamos en
"servantId". En el paso 6 transformamos este identificador en una referencia a 
objeto, es la misma informacin vista de otra forma, con el objetivo
de introducir esta referencia al objeto dentro del servidor de nombres.<br> 
Lo siguiente que tenemos que hacer es registrar esta referencia al
objeto Calculator  dentro del
servidor de nombres, ya que es all a donde va a acudir el cliente a buscar
la referencia al objeto.<br>
Para ello en el paso 7 se accede al servidor de nombres, paso idntico al
 2 del cliente. El paso 8 es tambin idntico al 3 del cliente, con la
excepcin de que aqu en vez de ejecutar "resolve()" sobre el
servidor de nombres ejecutamos "bind()", es decir, aqui unimos dentro
del servidor de nombres la referencia al objeto "Calculator" con el nombre
("Calculator","Example").<br>
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 implementacin
de la interfaz IDL adecuada. En nuestro caso si se recibe una invocacin 
para Calculator, el manager se la enviara a CalculatorImpl.<br>
Por ltimo en el paso 10 se invoca el mtodo "orb.run()" que cede el
control de la ejecucin al ORB para que puede comenzar a recibir
invocaciones del cliente. De este mtodo solo se vuelve en el caso de
que el ORB finalice, bien por salida provocada o por muerte.<br>
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 aplicacin.
La nica parte que se complicara algo ms sera la de creacin
de POAs y sus polticas asociadas. Todo lo dems es idntico siempre. 
<br>
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.<br>
<img src="servidor.gif">
<BR>
<B>Implementacin de Calculator</B><BR>
<BR>
Bueno, ya hemos alcanzado la parte fcil. La implementacin de
la interfaz IDL es tan sencilla como implementar una interfaz que no
fuera CORBA. Aqu va el cdigo:
<pre>
// ============================================================
// = Ejemplo de CORBA
// ============================================================

// Implementacion utilizando POA 

public class CalculatorImpl extends CalculatorPOA
{
  /**
   * Operacin add
   */
  public float add(float nb1, float nb2)
  {
    System.out.println("Suma = "+nb1+" + "+nb2);
    return nb1 + nb2;
  }

  /**
   * Operacin div
   */
  public float div(float nb1, float nb2)
    throws DivisionByZero
  {
    System.out.println("Division = "+nb1+" / "+nb2);

    if ( nb2 == 0 )
            throw new DivisionPorCero(nb1,nb2);

    return nb1 / nb2;
  }
}
</pre>
De este implementacin 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 aada todo el 
"skeleton" (esqueleto) utilizando herencia lo que permite que sea
accedido el objeto a travs de CORBA. 
Recordemos que este esqueleto se generaba de forma automtica de
la interfaz OMG/IDL utilizando el compilador "java2idl".
<br>
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.
<br>
<B>Ampliando el ejemplo</B><BR>
<BR>
Si quisieramos completar la interfaz de nuestra calculadora y aadir 
las operaciones de resta y multiplicacin sera muy sencillo.
<ol>
<li>Lo primero que haramos sera editar el fichero IDL "Calculator.idl" y
aadir dentro de las llaves de "interface Calculator {..}" :
<pre>
float resta ( in float nb1, in float nb2 );
float mult ( in float nb1, in float nb2 );
</pre>
Como ninguna de las dos levanta excepciones no hace falta utilizarlas.
<br>
<li>Una vez hecho esto volvemos a pasar el compilador "idl2java" para regenerar
los cabos y esqueletos.
<br>
<li>Por ltimo basta con implementar estas dos operaciones dentro de 
CalculatorImpl y ya podran ser utilizadas por cualquier cliente CORBA.
</ol>
Vemos con que facilidad se pueden ampliar las interfaces IDL, y vemos que 
estos cambios no afectan para nada al servidor de CORBA. Y el cliente CORBA
solo se ve afectado en el caso de que se elimine alguna operacin
de la interfaz que el utilice.
<br>
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
caractersticas fundamentales de CORBA. 
<br>
<B>Conclusiones del desarrollo</B><BR>
Como conclusin de este desarrollo CORBA podemos destacar
los siguientes puntos de la arquitectura CORBA. 
<ul>
<li>Facilidad de implementacin de las interfaces 
<li>Cdigo especfico CORBA muy parecido siempre 
<li>Facilidad de ampliacin de funcionalidad
<li>Transparencia total respecto a la distribucin (incluso excepciones)
<li>Potencial enorme: multilenguaje, multiarquitetcura, multiprotocolo
</ul>
<BR>
<BR>
<B>Prxima entrega</B><BR>
En la cuarta entrega del curso vamos a ver como la comunicacin
entre objetos Java y C++ es trivial gracias a CORBA.
Tambin introduciremos algn servicio ms 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 prximo nmero.
<BR>
<BR>
<B>Referencias</B><BR>
<BR>
<UL>
<LI>P&aacute;gina del curso: http://www.angelfire.com/al/acs</LI>
<LI>JavaORB: http://www.multimania.com/dogweb</LI>
<LI>JDK para GNU/Linux: http://www.blackdown.org</LI>
<LI>OMG: http://www.omg.org</LI>
</UL> 



