<-- Capítulo

Índice del tutor de Delphi
© Copyright 1998
por David Martínez.

Todos los derechos reservados

Capítulo -->

Capitulo 9.4. Mezclando Lenguajes y Plataformas con CORBA: Cómo Platicar con programas en Java

En éste capítulo veremos cómo podemos hacer que Delphi (Enterprise) y Java platiquen en CORBA. Además le servirá de práctica acerca de cómo hacer un programa en CORBA en Delphi sin utilizar MIDAS.

Este projecto utilizará dos programas (cliente y servidor) que estarán implementados en dos lenguajes (Delphi y Java). Como este es un curso de Delphi nos enfocaremos más a Delphi en cuanto a los detalles.

Para que los programas en Java en esta sección funcionen, usted necesitará JBuilder 3 Enterprise, Inprise AppCenter o algún SDK de Java (Enterprise Edition) que tenga las librerías de Visibroker instaladas apropiadamente.

La idea de hacer dos clientes y dos servidores tiene por objeto demostrar que podemos llamar al servidor de Java desde un cliente de Delphi y viceversa. Además, ver dos ejemplos en lenguajes diferentes le permitirá entender mejor hasta donde termina Delphi y donde comienza CORBA.

Un Servidor CORBA en Delphi

Como esta será una interfase muy simple, utilicemos Delphi para hacer un servidor. Simplemente creamos una nueva aplicación (le he cambiado el Título a la forma para que diga "Servidor de CORBA super-básico" y después seleccionamos File-New.

Seleccione la página de Multitier y "CORBA Object" a continuación.

A continuación Delphi le preguntará el nombre de clase de su objeto, de qué manera crearemos las instancias y el modelo de hilos de ejecución. Mi objeto se llama "ObjetoCurso" Para mantener las cosas simples, lo he hecho "Single Instance" y "Single-Threaded".

Seleccione OK y a continuación verá código como el que sigue:


  TObjetoCurso = class(TCorbaImplementation, IObjetoCurso)
  private
    { Private declarations }
  public
    { Public declarations }
  end;

implementation

uses CorbInit;

initialization
  TCorbaObjectFactory.Create('ObjetoCursoFactory',
 'ObjetoCurso', 'IDL:Project1/ObjetoCursoFactory:1.0', IObjetoCurso,
    TObjetoCurso, iSingleInstance, tmSingleThread);
end.

Esta es la implementación de su Objeto CORBA de acuerdo a Delphi. Todavía no hace nada ni implementa ninguna función, así que por ahora simplemente define un objeto que hereda de TCorbaImplementation, e implementa la interface IObjetoCurso. Como la interface todavía no tiene métodos, no necesitamos implementar nada.

En la inicialización de la unidad, Delphi crea una fábrica de Objetos (TCorbaObjectFactory.Create) y registra con la fábrica nuestro objeto. Delphi creará una interface CORBA llamada ObjetoCursoFactory y la "atará" a TCorbaObjectFactory.

En COM todos los objetos deben contar con una fábrica, pero en CORBA éste no es el caso (en CORBA una fábrica es simplemente una técnica específica de implementación, que no es requerida). Pero como Delphi utiliza el mismo código para generar objetos en COM y CORBA, mientras no implemente su servidor manualmente (con todas la complicaciones que esto genera), Delphi siempre creará una fábrica (llamada SuObjetoFactory) por usted. Esto es importante tener en cuenta cuando utilice otros lenguajes para conectarse a servidores en Delphi, como veremos más adelante.

Ahora que tenemos listo nuestro código inicial, comencemos por crear algunos métodos. Grabe su proyecto (yo grabé mi DPR "ORBDelCurso"), y a continuación seleccione "View-Type Library". El editor de librerías de tipos aparecerá a continuación. Notará que el editor de tipos es el mismo al mostrado en el Capítulo 6.6.

Utilice el botón con flecha verde para crear un nuevo método, y nómbrelo "DeCabeza". Lo que queremos hacer es una función que devuelva la cadena que ha recibido pero al revés.

Esta función recibirá un parámetro WideString y devolverá un parámetro WideString también, y para lograr esto necesitamos especificar dos parámetros, uno como "valor de regreso (retval)". Obviamente, uno es de entrada y otro es de salida:

También queremos hacer una función WideString llamada TuQuienEres para que nos diga si el servidor está usando Delphi o Java.

TuQuienEres no tiene parámetros, pero necesitamos declarar uno (out, retval) para satisfacer al editor de Tipos, que como es menso :-) cree que está lidiando con un IDispatch de COM y necesita que todas las funciones regresen un HResult (lo cual a nosotros, como programadores de CORBA, no nos interesa).

Ahora veamos el código que Delphi nos ha generado:


  TObjetoCurso = class(TCorbaImplementation, IObjetoCurso)
  private
    { Private declarations }
  public
    { Public declarations }
  protected
    function DeCabeza(const Cadena: WideString): WideString; safecall;
    function TuQuienEres: WideString; safecall;
  end;

implementation

uses CorbInit;

function TObjetoCurso.DeCabeza(const Cadena: WideString): WideString;
begin

end;

function TObjetoCurso.TuQuienEres: WideString;
begin

end;

Note como, aún cuando la librería de tipos nos hace especificar y dar nombre a parámetros de salida y nos obliga a especificar HRESULT como el tipo de retorno, nos ha definido las funciones correctamente (regresando WideString). Esto es porque aunque el editor de tipos está enfocado a COM, Delphi sabe cómo escribir CORBA adecuadamente. ¡Además esto nos permite exportar el objeto como objeto COM y convertirnos en un servidor COM y CORBA a la vez, cosa que ningún paquete hasta ahora ha permitido hacer!

Todo está listo para que implementemos nuestro programa. Simplemente llenamos los "begin... end"s de nuestras funciones con el código adecuado y listo:


function TObjetoCurso.DeCabeza(const Cadena: WideString): WideString;
var
  i : Integer;
begin

  Result := '';
  // Este for invierte los caracteres del mensaje
  for i := Length(Cadena) downto 0 do Result := Result + Cadena[i];

end;

function TObjetoCurso.TuQuienEres: WideString;
begin
  Result := 'Yo soy el objeto ObjetoCurso, implementado en Delphi';
end;

Felicidades! Acaba usted de crear su primer ORB!

Exportando IDL Para su Uso en Otros Lenguajes

Como mencioné en la sección teórica de interfases, las interfases se comunican hablando en el lenguaje IDL. Los servicios CORBA para todos los lenguajes de programación cuentan con convertidores de IDL al lenguaje y viceversa.

Para que nuestros clientes de Java se comuniquen con nosotros necesitaremos generar la especificación de nuestra interfase en lenguaje IDL. Para hacer esto utilizamos el botón de la esquina derecha en la barra de botones de la librería de tipos ("Export to IDL"). Éste botón exporta a COM IDL, pero tiene un menú junto al mismo (subrayado por la franja roja en la gráfica siguiente) que le permite seleccionar qué tipo de IDL quiere exportar. Selecciónelo y elija "Export to CORBA IDL".

El IDL que es exportado será como sigue:

module ORBDelCurso
{
  interface IObjetoCurso;


  interface IObjetoCurso
  {
    wstring DeCabeza(in wstring Cadena);
    wstring TuQuienEres();
  };

  interface ObjetoCursoFactory
  {
    IObjetoCurso CreateInstance(in string InstanceName);
  };

};

Grabe este archivo (he llamado al mío "OrbDelCurso.idl") Cuando hagamos nuestro cliente (y el servidor) en Java, necesitaremos el archivo para que Java nos genere el código apropiado (con la utilería "idl2java").

Si usted genera IDL manualmente o con algún ORB escrito en otro lenguaje, necesitará utilizar una utilería equivalente para generar el código "pas".

Hasta ahora (Diciembre 1999), no existe un programa para convertir IDL a Pascal (que se llamaría "IDL2PAS"). Inprise ha prometido este programa para una revisión futura de Delphi 5 Enterprise.

Un Cliente CORBA en Delphi

Ya que tenemos un servidor CORBA, podemos crear nuestro cliente. Como de costumbre, el cliente es más sencillo (en cuanto a la conexión de objetos) que el servidor. Para crear nuestro cliente sólo tenemos que incluir el archivo "OrbDelCurso_TLB.pas", que es nuestra especificación de la interfase en Pascal.

Comenzaremos por crear una simple interfaz de usuario con un EditBox y tres botónes, uno para conectar/desconectar, otro para llamar la función DeCabeza y otro para averiguar quién es nuestro servidor. También pondremos un memo para las respuestas.

Ahora, hacer el cliente es sencillísimo. Seleccione "Project-Add to Project" del menú de Delphi y navegue al directorio donde hizo el servidor. Añada el archivo "ORBDelCurso_TLB.pas" a su proyecto. Añada ORBDelCurso_TLB a su clausula de USES en la sección "interface" de su forma principal. Ahora, dentro de la forma del cliente (ya sea en private o public) declare una variable de tipo IObjetoCurso (el mío se llama ObjetodelCurso).

Ahora la única línea de código que necesita escribir es:


     ObjetodelCurso :=  TObjetoCursoCorbaFactory.CreateInstance('');

Donde desee hacer la conexión. A partir de entonces, su variable será un objeto al cual usted puede llamar como cualquier otro objeto de Delphi, como por ejemplo este código, que pone el resultado a la llamada remota "DeCabeza" en el Memo, utilizando como parámetro nuestro campo de edición:


  // De Cabeza
  Memo1.Lines.Add(ObjetoDelCurso.DeCabeza(Edit1.Text));

En el momento de la conexión (CreateInstance), Delphi buscará en el subnet local cualquier objeto que soporte ObjetoCursoFactory, y ejecutará la función CreateInstance para obtener un "ObjetoCurso", que es el objeto que nosotros definimos.

Esto quiere decir que usted puede ejecutar una o varias veces su servidor en alguna computadora de su red TCP/IP y sus clientes lo encontrarán "mágicamente", sin necesidad de mencionar una computadora.

Ejecutando un servidor escrito en Visibroker

Para poder ejecutar el servidor, usted necesitará tener el servicio SmartAgent ejecutando. Si su servicio SmartAgent no está presente o no está configurado al mismo puerto TCP que su objeto CORBA (vea el "Smart-Agent Reg-Edit tool" en su folder de Visibroker en el menú de inicio), el programa no ejecutará (porque Delphi se quedará esperando a que un servicio de nombres Visibroker conteste).

Así que, ejecute su "Visibroker Smart Agent" (que es el registro de objetos de Visibroker). Se encuentra en el menú de inicio, en el Subgrupo de "Visibroker" en su Delphi 4 o 5 Enterprise. SmartAgent muestra una ventana blanca sin ningún mensaje.

Ahora ejecute su servidor y su cliente (posiblemente en máquinas diferentes) y diviértase!

He aquí una imagen de mi cliente en acción (mi servidor también está funcionando):

Un Cliente CORBA en Java

A continuación veremos cómo implementar un cliente en Java. Como este curso no está enfocado a Java, sólo explicaré cómo generamos nuestro código con idl2java, como conectarnos al servidor, y cómo accesamos nuestro objeto desde Java, sin explicar gran cosa acerca de como compilar, cómo funcionan los botónes, etcétera. Pero he incluido en el Zip el código fuente en Java también, para que usted lo pueda ver y examinar.

Para que los programas en Java en esta sección funcionen, usted necesitará JBuilder 3 Enterprise, Inprise AppCenter o algún SDK de Java (Enterprise Edition) que tenga las librerías de Visibroker instaladas apropiadamente. Utilice el comando vbj en vez del comando java y el comando vbjc en vez de javac para asegurarse de que las librerías de Visibroker están siendo utilizadas.

Como mencionamos con anterioridad, primero debemos convertir el IDL que generamos al crear el servidor de Delphi al lenguaje que usaremos para conectarnos, en este caso Java. Así que ejecutamos "idl2java ORBDelCurso.idl" en la línea de comando. En el caso de IDL2Java, nos generará un directorio con el nombre del módulo de CORBA, en este caso "ORBDelCurso". Este directorio es un paquete de Java al que podemos hacer referencia en nuestro código.

Como hemos visto con anterioridad, los clientes son más fáciles de implementar que los servidores. Ahora que tenemos el paquete que nos dice cómo pedirle a CORBA que utilice el objeto sólo tenemos que crear un ObjetoCursoFactory y pedirle que nos genere un ObjetoCurso. Idl2Java ya nos ha escrito este código, y lo ha puesto en la clase ObjetoCursoFactoryHelper.

Así que, para implementar un cliente que utilice el objeto que hemos escrito en Delphi, debemos instanciar un objeto con el FactoryHelper, y después llamar a CreateInstance en el objeto (por aquello de que Delphi siempre usa Fábricas de clases) para obtener nuestro objeto del curso. Por ejemplo:


  ORB orb;
  ObjetoCursoFactory fac;
  IObjetoCurso obj;

  orb = ORB.init(args, null);
  fac = ObjetoCursoFactoryHelper.bind(orb, null);
  obj = fac.CreateInstance("");

Éste pedacito de Código en Java:

He creado un pequeño cliente en Java que usted puede ejecutar si tiene Visibroker for Java o JBuilder utilizando la línea de comando "vbj ClienteORB usabind".

En el código en Java que he escrito, he añadido un parámetro, "usabind" (en minúsculas) para que la utilización de bind sea opcional (bind nos conecta con el SmartAgent). Si usted no especifica "usabind", el programa buscará un archivo .ior en el directorio ".." (padre) y lo utilizará en vez de usar un servicio de nombres. Esto le permite a su código en Java correr sin necesidad de Visibroker (utilizando el ORB nativo del JDK). Pero obviamente, no podrá conectarse a los programas equivalentes en Delphi, que sí lo requieren. Recuerde usar usabind en este caso en particular!

Un Servidor CORBA en Java

Ahora que hemos probado que nos podemos comunicar entre Delphi y Java, tratemos de crear un servidor en Java, para tener las cuatro piezas y poder examinar cómo funciona todo esto.

Los pasos para hacer funcionar un servidor en Java son:

Hé aquí el código:


class ObjetoCursoServidor extends ORBDelCurso._ObjetoCursoFactoryImplBase {
...
    public static void main( String[] args ) {
    try
    {

       ORB orb = ORB.init( args, null );
       System.out.println(orb.getClass().getName());
       BOA boa = orb.BOA_init();
       System.out.print("ORB inicializado.");
       ObjetoCursoServidor impl = new ObjetoCursoServidor("ObjetoCurso");
       System.out.print(impl.toString()+"\n");
       boa.obj_is_ready(impl);
       String ior = orb.object_to_string(impl);
       boa.impl_is_ready();

     } catch ( SystemException sysx ) {
       System.err.println(sysx);
     }
...

La fábrica sólo tiene una función, que se llama CreateInstance. Delphi nos había ahorrado el tener que implementar el CreateInstance, pero como estamos en java lo debemos hacer manualmente. Afortunadamente es muy fácil:


   public IObjetoCurso CreateInstance(String instanceName) {
       IObjetoCurso resultado = new ObjetoCurso();
       return ( resultado );
   };

Obviamente, ahora necesitamos hacer un ObjetoCurso.java que responda a las peticiones del cliente. Idl2Java también nos ha escrito una base que podemos extender, así que simplemente hacemos una clase que extienda _IObjetoCursoImplBase e implemente nuestras funciones "DeCabeza" y "TuQuienEres".

Ahora lo podemos ejecutar y pedir al cliente de Delphi (o al de Java) que se conecte. Para ejecutarlo las reglas son las mismas que con Delphi. El SmartAgent tiene que estar ejecutando. Usted puede ejecutarlo con la línea de comando "vbj ObjetoCursoServidor".

He aquí al cliente de Delphi conectado a un servidor de Java. El funcionamiento es idéntico (ni siquiera tuvimos que recompilar o decirle a Delphi que Java "existe") y la única diferencia es que "TuQuienEres" devuelve una cadena diferente.

Como podrá deducir, esto es poderosísimo! Ahora puede usted utilizar toda la facilidad de uso de Delphi para programar clientes o servidores en varios ambientes (Java no es el único lenguaje con el que podemos platicar; CORBA existe para Mainframes, Unix y para muchos lenguajes "tradicionales" como COBOL y otros), y communicarse entre un ambiente y otro con muy pocas dificultades, y en tiempo real. Si encuentra que JDBC es más potente que Delphi en el servidor, o que prefiere utilizar Java en el cliente porque algunos de sus usuarios utilizan Mac, Unix o Linux, usted puede simplemente exportar la interfase y conectarse, sin necesidad de reescribir aplicaciones completas.

Con todo esto, apenas hemos tocado la punta del iceberg en cuanto a CORBA y Visibroker. Espero que esto le haya picado la curiosidad de investigar el gran mundo de la computación de grande empresa.

Copiar el Código fuente (74K, formato Zip) para esta sección

Capítulo -- >