Mi Desktop

Snapshot
G.I.R.

Impacto Visual

iv(273).jpg

Dicen los que saben

Sin música la vida sería un error.

Friedrich Nietzsche

Encuesta

Paranoid Puppets
 

Syndicate

Estadisticas

OS: Linux
PHP: 5.2.11
MySQL: 5.0.84-percona-highperf-b18
Time: 06:36
Caching: Disabled
GZIP: Disabled
News: 177
Visitors: 163422
We have 2 guests online

Start arrow Tutoriales
Tutoriales
CORBA - omniORB - Tutorial 02 E-mail
viernes, 24 julio 2009

Es de suma importancia que antes de continuar, echen un vistazo al primer tutorial de CORBA-omniORB, en el encontraran todo lo necesario para la instalacion y puesta en marcha.

CORBA - omniORB - Tutorial 01

Ok, continuemos.

En ese primer tutorial hablamos sobre como compilar, instalar y ejecutar omniORB, incluimos un pequeño ejemplo.

Esta vez explicaremos, el ejemplo linea por linea, o al menos las secciones que se deben de mencionar; ademas de que mostraremos la interoperabilidad de CROBA, usando C++ en el cliente y Python en el servidor.

Lo primero que debemos hacer es crear un archivo .idl, conocido como interface description lenguage. Lo llamamos SQL.idl.


module SQL
{
        interface SQLQuery
        {
                string Query(in string query);
        };
};


Aqui definimos una interfaz comun que usaran los programas, osea, que se ponen de acuerdo como seran los metodos que se utilizaran, si repasamos el codigo vemos que se activa un modulo el cual tiene una interfaz con un solo metodo que como parametro recibe un string de nombre query y regresa un string.

Ya que tenemos este archivo, necesitamos generar los archivos "back-end", que son los que se encargan del trabajo rudo y a nosotros solo nos toca implementar y usar el metodo que declaramos.

$omniidl -bpython -CPyhton SQL.idl

$omniidl -bcxx -CC++ SQL.idl

Los parametros -bpyhton o -bcxx sirven para generar los "back-ends" para dicho lenguaje, la parte de -CPython y -CC++ es para cambiar de directorio antes de generar los archivos (los directorios deben de existir), esto sirve para tener bien organizado el codigo; y el ultimo parametro es el archivo.idl

Antes de continuar expliquemos algo de simbologia:

La explicacion del codigo esta en verde, este texto quitalo del codigo fuente para que funcione.

El codigo usa los colores de resaltado de vim y la letra es de diferente tamaño y fuente (Tahoma).

Los nombres y variables a las que hay que ponerle atencion estan en negritas y cursiva

Ya que tenemos los archivos basicos para C++ y Python nos pasamos al directorio de Python y creamos un archivo llamado Servidor.py

Dentro de el colocamos el siguiente codigo:


#!/usr/bin/env python

Comenzamos agregando los imports necesarios.

import sys
import CosNaming
import SQL ,SQL__POA
import MySQLdb
from omniORB import CORBA, PortableServer

Definimos una clase con el nombre SQLQuery_i, que es el que definimos en nuestro archivo .idl, mas _i.

class SQLQuery_i(SQL__POA.SQLQuery):

Dentro de el debemos implementar el metodo Query, que definimos para nuestra interfaz en el archivo .idl, asi cualquier cliente podra solicitar los servicios, debemos recordar que definimos que recibia un string (qry) y regresaba un string (res).

        def Query(self, qry):

Mostramos el saludo que nos envio el cliente y hacemos lo mismo.

                print "Saludo recibido -> " , qry
                return "Hola, Soy Python"

Una vez definida la clase y como se implementan los metodos debemos de comenzar a trabajar con CORBA. Antes que nada debemos crear un objeto, al cual le pasamos los argumentos que recibimos de la linea de comandos por medio de la variable sys.argv, ademas del identificador de la implementacion de CORBA que estamos usando.

orb = CORBA.ORB_init(sys.argv, CORBA.ORB_ID)
poa = orb.resolve_initial_references("RootPOA")

A continuacion creamos un objeto del tipo SQLQuery_i, que definimos al inicio del programa.

implemetacionSQLQuery = SQLQuery_i()
objetoSQLQuery = implemetacionSQLQuery._this()

La siguiente parte explica como dar de alta un servicio en el servidor de nombres de omniNames, para que los clientes puedan invocar los objetos con el nombre del servicio, estos nombres deben de ser consistentes tanto en el servidor como el cliente.

Primero buscamos una referencia con el nombre ServicioSQL y creamos un contexto raiz. Nota: esto cobrara mayor sentido cuando discutamos como se ejecuta el programa.

obj = orb.resolve_initial_references("ServicioSQL")
rootContext = obj._narrow(CosNaming.NamingContext)

if rootContext is None:
        print "No se pudo inicar el Contexto \"Root\""
        sys.exit(1)

Ya que tenemos un contexto raiz, creamos un nombre para este.

nombre = [CosNaming.NameComponent("SD", "Contexto")]

try:

Asociamos el contexto raiz con el que usaremos, que llamaremos SQLContext

        SQLContext = rootContext.bind_new_context(nombre)
        print "Nuevo contexto creado"

except CosNaming.NamingContext.AlreadyBound, ex:

Esta excepcion se dispara si el contexto raiz ya existe, en ese caso, busca que el nombre que le asignamos ("SD"-"Contexto"), para re-utilizarlo.

        print "El contexto ya existe"
        obj = rootContext.resolve(nombre)
        SQLContext = obj._narrow(CosNaming.NamingContext)
        if SQLContext is None:
                print "EjemploEcho.Objeto existe pero no es un Nombre de Contexto"
                sys.exit(1)

Despues de nombrar el contexto raiz, debemos agregar el componente y el nombre con el que los identificaremos.

nombre = [CosNaming.NameComponent("SQL", "SQLQuery")]

try:

Ahora lo asociamos con el contexto raiz que creamos antes.

        SQLContext.bind(nombre, objetoSQLQuery)
        print "Bind"

except CosNaming.NamingContext.AlreadyBound:

Una vez mas, si el contexto ya existe, solo lo volvemos a agregar y listo.

        SQLContext.rebind(nombre, objetoSQLQuery)
        print "Rebind"

Iniciamos el manejador de objetos e iniciamos el orb.

poaManager = poa._get_the_POAManager()
poaManager.activate()

orb.run()


Ya hemos terminado con el servidor, vamos a hacer el cliente, recordemos que este se hara en C++; asi que nos pasamos a la carpeta de C++ y creamos un archivo llamado Cliente.cpp y agregamos el siguiente codigo:


Agregamos las cabeceras y declaramos los espacios de nombres que usaremos.

#include <iostream> #include <string>
#include "SQL.hh"

using namespace std;
using namespace SQL;

Declaramos las funciones prototipo, la primera sera con la que obtendremos la referencia al objeto que creamos en servidor con Python, usando los nombres que declaramos en dicho programa.

La segunda sera la funcion que llamara a un metodo del objeto en el servidor, es por eso que pasamos una referencia al objeto y el string con el saludo.

CORBA::Object_ptr getReferenciaObjeto(CORBA::ORB_ptr orb);
void query(SQLQuery_ptr refSQLQuery, const string qry);

int main(int argc, char** argv)
{
        try
        {

Iniciamos el orb, con los parametros que recibimos en la linea de comandos.

                CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);

Llamamos ala funcion getReferencia, para obtener el apuntador al objeto del servidor.

                CORBA::Object_var obj = getReferenciaObjeto(orb);

Ya que tenemos el puntero, debemos convertirlo a uno del tipo SQLQuery, que es el nombre de la clase que declaramos en Pyhton para asi poder llamar a los metodos que tiene definidos.

                SQLQuery_var referenciaSQLQuery = SQLQuery::_narrow(obj);

Creamos el saludo.

                string qry = "Hola, Soy C++";

Llamamos a la funcion query para que haga la peticion, recordemos que debemos de pasar la referencia al objeto SQLQuery.

                query(referenciaSQLQuery, qry);

Destruimos el objeto, para finalizar.

                orb->destroy();
        }

El resto es manejo de excepciones.

        catch (CORBA::TRANSIENT&)
        {
                cerr << "Exception del Sistema TRANSIENT -> no se pudo contactar el servidor." << endl;
        }
        catch (CORBA::SystemException& ex)
        {
                cerr << "Excepcion del Sistema CORBA::" << ex._name() << endl;
        }
        catch (CORBA::Exception& ex)
        {
                cerr << "CORBA::Exception: " << ex._name() << endl;
        }
        catch (omniORB::fatalException& fe)
        {
                cerr << "Excepcion omniORB::fatalException:" << endl;
                cerr << " Archivo: " << fe.file() << endl;
                cerr << " Linea: " << fe.line() << endl;
                cerr << " Mensaje: " << fe.errmsg() << endl;
        }
        return 0;
}

Ahora implementamos el metodo que llamara al metodo Query del objeto remoto.

void query(SQLQuery_ptr refSQLQuery, const string qry)
{

Verificamos que en verdad exista la referencia hacia el objeto.

        if (CORBA::is_nil(refSQLQuery))
        {
                cerr << "La referencia del objeto es nula" << endl;
                return;
        }

Aqui es donde viene lo interesante.

Hasta este momento hemos utilizados el tipo de variable std::string (standard C++), pero para que el texto que mandamos al metodo en el objeto remoro sea compatible, debemos de utilizar el tipo CORBA::String_var (omniORB) para que Python reciba la informacion como se debe.

        CORBA::String_var mensaje = qry.c_str();

Y mandamos llamar el metodo Query, del objeto remoto y el resultado, lo guardamos en una variable del tipo CORBA::String_var.

        CORBA::String_var res = refSQLQuery->Query(mensaje);

Finalmente mostramos el resultado. Notemos que la variable del tipo CORBA::String_var, contiene una sobre carga del operado << para que std::cout funcione.

        cout << "Mensaje enviado -> " << mensaje << endl;
        cout << res << endl;
}

Hagamos el ultimo metodo, el cual se encarga de resolver las referencias y los nombres de los objetos y componentes remotos. Mucho de este trabajo, se asemeja al que ya hicimos en Pyhton, solo hay que traducirlo a C++.

CORBA::Object_ptr getReferenciaObjeto(CORBA::ORB_ptr orb)
{

Primero creamos un contexto raiz.

        CosNaming::NamingContext_var rootContext;

        try
        {

Obtenemos la referencia al servicio "ServicioSQL". Nota: como lo dijimos en la seccion de Python, esto cobrara mayor sentido cuando discutamos como se ejecuta el programa.

                CORBA::Object_var obj;
                obj = orb->resolve_initial_references("ServicioSQL");

Y nuestro contexto raiz lo asociamos con la referencia a "ServicioSQL".

                rootContext = CosNaming::NamingContext::_narrow(obj);

El resto es solo manejo de errores.

                if(CORBA::is_nil(rootContext))
                {
                        cerr << "Fallo en narrow" << endl;
                        return CORBA::Object::_nil();
                }
        }
        catch (CORBA::NO_RESOURCES&)
        {
                cerr << "Excepcion NO_RESOURCES. Quizas debas configurar omniORB con el path del servicio de Nombres" << endl;
                return 0;
        }
        catch(CORBA::ORB::InvalidName& ex)
        {
                cerr << "El servicio solicitado es invalido [nt existe]." << endl;
                return CORBA::Object::_nil();
        }

¿Recuerdan los nombres que usamos en el servidor?

Debemos de usar los mismos, para que se puedan comunicar, imaginemos lo siguiente como un pequeño arbol con una raiz, del cual se desprenden componentes, de diferentes tipos.

Creamos el nombre que se usara por el servidor de nombres (omniNames, ver Tutorial 01).

        CosNaming::Name nombre;
        nombre.length(2);

        nombre[0].id = (const char*) "SD";
        nombre[0].kind = (const char*) "Contexto";
        nombre[1].id = (const char*) "SQL";
        nombre[1].kind = (const char*) "SQLQuery";

        try
        {

Y en nuestro contexto raiz, que contiene la informacion del servicio ("ServicioSQL" y una IP), tratamos de resolver los nombres de los servicios. Y regresamos un puntero al objeto encontrado con las caracteristicas especificadas.

        return rootContext->resolve(nombre);
        }

Y verificamos errores.

        catch(CosNaming::NamingContext::NotFound& ex)
        {
                cerr << "No se encontro el Contexto." << endl;
        }
        catch(CORBA::TRANSIENT& ex)
        {

                cerr << "Excepcion del Sistema, no se pudo contactar el servidor de nombres, asegurate que esta corriendo y omniORB esta bien configurado" << endl;
        }
        catch(CORBA::SystemException& ex)
        {
                cerr << "Excepcion de CORBA::" << ex._name() << " al usar el servidor de nombres." << endl;
                return 0;
        }
        return CORBA::Object::_nil();
}


Ya tenemos el cliente listo solo nos basta compilarlo, para poder comenzar la prueba, para esta tarea nos ayudaremos de la famosa herramienta, make; asi que debemos de crear dentro de la misma carpeta (C++) el archivo Makefile y colocar el siguiente texto:


LIBS += -lomniORB4 -lomnithread -lomniDynamic4
OPS += -Wall -pipe -O2
CXX = g++

all: Cliente

Cliente: SQLSK.o Cliente.o
        $(CXX) $(LIBS) $^ -o $@

SQLSK.o: SQLSK.cc
        $(CXX) -c $(OPS) $^ -o $@

Cliente.o: Cliente.cpp
        $(CXX) -c $(OPS) $^ -o $@

clean:
        rm -f *.o Cliente


Ejecutamos el make.

$make

Pues ya tenemos todo listo, Servidor, Cliente y si seguimos el primer tutorial, omniORB esta listo, ademas de que el servidor de nombres, omniNames, tambien esta funcionando, asi que solo debemos de arrancar cada uno de los programas.

Comencemos con el servidor

$ python Servidor.py -ORBInitRef ServicioSQL=corbaname::localhost

Lo que hacemos es iniciar el codigo Python, pasandole la referencia inicial, que en este caso es un servicio llamado "ServicioSQL" y que se encuentra en localhost, osea en nuestra maquina.

Recordemos que al iniciar el ORB, en Python como en C++ le deciamos que resolviera la referencia inicial y le decimas el nombre del servicio (en los 2 fue ServicioSQL), pues ese nombre es el que pasamos como parametro para que el programa y el servidor de nombres (omniNames) sepan sobre que o quien estamos vamos a trabajar.

La salida sera:

Nuevo contexto creado

Bind

Y despues de ejecutar el cliente

Saludo recibido -> Hola, soy C++

Ahora el cliente.

$ ./Cliente -ORBInitRef ServicioSQL=corbaname::196.168.10.5

Es muy parecido al anterior, solo que esta vez le decimos que el "ServicioSQL" lo encuentra en la direccion IP especificada.

Nota: Esta es una IP de ejemplo, para ejecutarlo en una sola maquina tambiin hay que ponerle localhost, pero si lo hacemos en una red, ponemos la IP de la computadora que esta ejecutando el servidor.

La salida sera:

Mensaje enviado -> Hola, soy C++

Hola, soy Python

Pues ya esta, recuerda consultar la documentacion que viene con los codigos fuente, esta muy buena y este ejemplo se baso en ella.

 
© 2009 scumbag > scmbg
Joomla! is Free Software released under the GNU/GPL License.