jueves, 1 de octubre de 2009

Creando una aplicación CORBA completa con Java e IDL

Hace poco una amiga me pregunto si sabia programar en java a lo que respondí: "Obviamente, me estas ofendiendo ;)", y me comento que necesitaba un programa que sume dos números, yo dije dentro de mi "no hay algo un poco mas difícil??", pero con lo que no contaba es con la línea final que me escribió en la conversación "pero lo quiero usando CORBA en java", mmm hace mucho que no veía corba y me pareció interesante la idea de escribir al respecto y de paso que como buen samaritano ayudaba a mi querida amiga "la chata", esta va por ella .....

En principio vayamos a la definición de CORBA, santa wikipedia dice lo siguiente "En computación, CORBA (Common Object Request Broker Architecture - arquitectura común de intermediarios en peticiones a objetos), es un estándar que establece una plataforma de desarrollo de sistemas distribuidos facilitando la invocación de métodos remotos bajo un paradigma orientado a objetos.", esto en buen cristiano quiere decir que los métodos públicos de la instancia de una clase que ustedes escriban (siguiendo las especificaciones de corba) en el servidor pueden ser llamados remotamente desde una aplicación en una pc cliente, estas clases pueden escribirse en distintos lenguajes es decir que uno podría escribir las clases en c++ en el servidor y las instancias de estas clases podrían ser llamadas por un cliente el cual dispone de las clases escritas en java.

IDL es un lenguaje de definición de interfaces que utiliza CORBA, el cual le permitirá definir las interfaces para los servicios que ofrecerá, de estas interfaces parten las implementaciones de la parte servidor y cliente en cualquiera de los diversos lenguajes que implementan CORBA (Ada, C, C++, Smalltalk, Java, Python, Perl).

Y bueno Java es Java no tengo mas que decir...

Ahora si a lo que importa la implementación:

PASO 1: Preparar la aplicación
Crear una carpeta donde prefieran para trabajar las clases dentro de ella en mi caso estoy sobre una maquina con windows asi es que trabajare en la carpeta "d:’aplicaciones’corba’java’sumadosnumeros"

PASO 2: Definir la interfaz IDL
ya dentro de la carpeta crearemos un archivo llamado Suma.idl con el famosísimo Notepad (de cariño Visual Notepad), el cual tiene el siguiente contenido:

   1: module sumaApp{
   2:     interface suma{   
   3:         long sumar(in long primernumero, in long segundonumero);
   4:         oneway void shutdown();
   5:     }   
   6: }

Traduciendo el código diría algo así: creamos dentro de la carpeta sumaApp las clases necesarias para implementar en corba la interface suma que tiene dos métodos sumar que devuelve un entero (long), con dos parámetros de entrada (in) primernumero que es entero y segundo numero que también es entero, método que nos permitirá sumar dos números enteros, y el método shutdown que nos permitirá cerrar la transacción cuando lo necesitemos.

PASO 3: Generar las clases CORBA
Para generar las clases corba utilizaremos el compilador de interfaces que viene con el sdk de java se llama idlj, al ejecutar esta aplicación en conjunto con la definición suma.idl creara para nosotros todas las clases necesarias para poder utilizarla. El procedimiento es como sigue:

dentro de la carpeta de la aplicación ejecutar: idlj -fall suma.idl

esta generara la carpeta sumaApp y dentro de ella las clases _SumaStub.java, Suma.java, SumaHelper.java, SumaHolder.java, SumaOperations.java, SumaPOA.java

* tengan en cuenta que el directorio bin de java debe estar en las variables de entorno si no lo esta tendría que ejecutar algo así dentro de la carpeta de su aplicación: c:’ProgramFiles’java’jdk1.6.0_14’bin’idlj -fall suma.idl, esto seria para todos los comandos que usaremos en adelante

ahora solo tenemos que escribir la clase cliente y la clase servidor dentro de carpeta de la aplicación

PASO 4: La clase servidor: SumaServer.java

   1: import sumaApp.*;
   2: import org.omg.CosNaming.*;
   3: import org.omg.CORBA.*;
   4: import org.omg.PortableServer.*;
   5: import org.omg.PortableServer.POA;
   6:  
   7: class SumaImpl extends SumaPOA{
   8:     private ORB orb;
   9:  
  10:     public void setORB(ORB orb_val){
  11:         orb=orb_val;
  12:     }
  13:  
  14:     public int sumar(int primernumero, int segundonumero){
  15:         return primernumero+segundonumero;
  16:     }
  17:  
  18:     public void shutdown(){
  19:         orb.shutdown(false);
  20:     }
  21: }
  22:  
  23: public class SumaServer {
  24:  
  25:     public static void main(String args[]){
  26:         try{
  27:             ORB orb= ORB.init(args,null);
  28:             POA rootpoa=POAHelper.narrow(orb.resolve_initial_references("RootPOA"));
  29:             rootpoa.the_POAManager().activate();
  30:  
  31:             SumaImpl sumaImpl=new SumaImpl();
  32:             sumaImpl.setORB(orb);
  33:  
  34:             org.omg.CORBA.Object ref=rootpoa.servant_to_reference(sumaImpl);
  35:             Suma href=SumaHelper.narrow(ref);
  36:             org.omg.CORBA.Object objRef=orb.resolve_initial_references("NameService");
  37:             NamingContextExt ncRef=NamingContextExtHelper.narrow(objRef);
  38:  
  39:             String name="Suma";
  40:             NameComponent path[]=ncRef.to_name(name);
  41:             ncRef.rebind(path, href);
  42:             System.out.println("Servidor de suma listo y en espera");
  43:             orb.run();
  44:         }catch(Exception e){
  45:             System.err.println("Error: "+e);
  46:             e.printStackTrace(System.out);
  47:         }
  48:  
  49:         System.out.println("Adios cerrando servidor");
  50:     }
  51: }

si vemos detenidamente el código en este archivo notaremos que se implementan dos clases SumaImpl y SumaServer, SumaImpl es la que se encarga de implementar los métodos declarados en la interface en el archivo idl que definimos al principio. La clase SumaServer se encarga de generar las llamadas a los métodos corba haciendo referencia siempre a la clase SumaImpl que es la que llevara toda la lógica de la aplicación. Es decir que la clase SumaServer en si es repetitiva a diferencia de la clase SumaImpl que es donde implementaremos la logica de los métodos que utilizaremos

* No explicare el código ya que por ser pequeño asumiré que es entendible

PASO 5: la clase Cliente: SumaClient.java

   1: import sumaApp.*;
   2: import org.omg.CosNaming.*;
   3: import org.omg.CORBA.*;
   4:  
   5: public class SumaClient {
   6:  
   7:     static Suma sumaImpl;
   8:  
   9:     public static void main(String args[]){
  10:         try{
  11:             ORB orb= ORB.init(args,null);
  12:             org.omg.CORBA.Object objRef=orb.resolve_initial_references("NameService");
  13:             NamingContextExt ncRef= NamingContextExtHelper.narrow(objRef);
  14:     
  15:             String name="Suma";
  16:             sumaImpl=SumaHelper.narrow(ncRef.resolve_str(name));
  17:             //System.out.println("Obteniendo las cabeceras del objeto servidor: "+sumaImpl);
  18:             System.out.println("suma es:"+Integer.toString(sumaImpl.sumar(20, 30)));
  19:             sumaImpl.shutdown();
  20:         }catch(Exception e){
  21:             System.out.println("Error: "+e);
  22:             e.printStackTrace(System.out);
  23:         }
  24:     }
  25: }

La clase SumaClient también es sencilla dentro de la etiqueta try se realiza la construcción de los objetos CORBA y si vemos bien el llamado a la función de suma se hace casi en la ultima línea que es la única que en realidad cuenta como lógica de programa ya que la parte de construcción de objetos corba es repetitiva para la mayoría de los casos

ULTIMO PASO: Probar

Primero tenemos que compilar nuestras clases para ello usaremos la siguiente línea estando dentro de la carpeta donde esta nuestra aplicación:
javac *.java sumaApp/*.java

si no hay alertas entonces vamos por buen camino (al menos a mi no me salió ninguna)

ahora ya compilado iniciaremos el servicio orbd (asegúrense de ser administradores sino no podrán iniciar el servicio), la linea es la siguiente:
orbd -ORBInitialPort 1080
si eso no funciona pueden usar:
start orbd.exe -ORBInitialPort 1080

* ordb.exe viene en la carpeta bin del sdk de java

si todo va bien el servicio orbd se iniciara escuchando en el puerto 1080 (ustedes pueden elegir que puerto usar de los 65000 disponibles)

Ahora tenemos que iniciar nuestro servidor de sumas dentro del servicio orbd, la línea es la siguiente:
java SumaServer -ORBInitialPort 1080 -ORBInitialHost localhost

si les sale el mensaje: "servidor de suma listo y en espera" todo va bien

y como final solo tenemos que ejecutar el cliente para verificar que todo funcione, la línea es como sigue:
java SumaClient -ORBInitialPort 1080 -ORBInitialHost localhost

y debería de mostrarnos en pantalla el texto "la suma es : 50", ya que como parámetros le pasamos 30 y 20 en el código del cliente, si obtienen eso entonces ya tienen el trabajo echo

Por cuestiones pedagógicas ejecutamos el cliente y el servidor en la misma maquina lo cual no es lo ideal, para que puedan ustedes ver lo que realmente significa corba deben de llevar a otra maquina la carpeta de aplicación y desde la otra maquina ejecutar el cliente

También dejo en claro que esta aplicación es de las mas sencillas de entender y la escribí pensando en cuestiones pedagógicas, y seguramente los gurús del corba deben de tener mejores códigos comparados con este que es a mi parecer humilde pero efectivo.

Con esto terminamos pensé hacerlo en una hora pero me tomo 3 y ya son las 3 am asi es que me voy a dormir, nos vemos y hasta que por ahí se me ocurra escribir de nuevo

Saludos