[Off-topic]Tutorial Apache Thrift entre Java y C++

Después de haber instalado apache thrift (Instalación Apache Thrift), vamos a hacer un ejemplo.

Apache thrift utiliza un archivo con extensión thrift para definir los métodos que utilizaran los lenguajes para comunicarse, en el que su definición es muy parecida a C. En la pagina oficial hay un archivo con todo lo que necesitamos saber, como definir los tipos de datos por ejemplo.

Vamos a definir un archivo thrift para nuestro ejemplo:


/**
  32  * The first thing to know about are types. The available types in Thrift are:
  33  *
  34  *  bool        Boolean, one byte
  35  *  i8 (byte)   Signed 8-bit integer
  36  *  i16         Signed 16-bit integer
  37  *  i32         Signed 32-bit integer
  38  *  i64         Signed 64-bit integer
  39  *  double      64-bit floating point value
  40  *  string      String
  41  *  binary      Blob (byte array)
  42  *  map  Map from one type to another
  43  *  list    Ordered list of one type
  44  *  set     Set of unique elements of one type
  45  *
  46  * Did you also notice that Thrift supports C style comments?
  47  */

//nombre del paquete en el que va ir nuestro código
namespace java ejemplothrift
//nombre de la clase que creara thrift
service EjemploT{

//vamos a definir los metodos que usaran los dos lenguajes

void ping(),

string obtener_posicion(1:i32 pos),

i32 sumar(1:i32 uno, 2:i32 dos)

}
Lo guardamos como ejemplo.thirft. Como se puede observar, solo definimos el nombre de los métodos, el tipo de retorno, y el tipo de parámetros. Los parámetros van numerados, acompañados del tipo de datos que sera y el nombre del mismo. Hay muchas cosas que podemos hacer con thrift, pero para un ejemplo básico solo iniciaremos con esto.

Ya definidos nuestro archivo thrift, ahora lo compilaremos. En consola introducimos lo siguiente thrift -r --gen cpp ejemplo.thift  donde:

  • thrift es el comando indicando que utilizaremos el programa
  • -r para que sea recursivo
  • --gen indicando la generación del código
  • cpp el lenguaje que queremos que cree
  • ejemplo.thrift el archivo thrift con nuestras configuraciones.
con esto, podremos ver que nos ha creado una carpeta con como 5 archivos, todos generados por apache thrift.

Creamos un proyecto con QTcreator y copiamos los archivos creados por apache a nuestro proyecto y los agregamos, dando click derecho sobre nuestro proyecto dentro de QT, agregar archivos existentes, y seleccionar los que acabamos de copiar.

Veremos que entre los archivos hay uno que termina con el nombre skeleton. Este archivo es toda la base que necesitamos para crear nuestro servidor con c++.  



 // This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.

#include "EjemploT.h"
#include 
#include 
#include 
#include 

using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;

using boost::shared_ptr;

class EjemploTHandler : virtual public EjemploTIf {
 public:
  EjemploTHandler() {
    // Your initialization goes here
  }

  void ping() {
    // Your implementation goes here
    printf("ping\n");
  }

  void obtener_posicion(std::string& _return, const int32_t pos) {
    // Your implementation goes here
    printf("obtener_posicion\n");
  }

  int32_t sumar(const int32_t uno, const int32_t dos) {
    // Your implementation goes here
    printf("sumar\n");
  }

};

int main(int argc, char **argv) {
  int port = 9090;
  shared_ptr handler(new EjemploTHandler());
  shared_ptr processor(new EjemploTProcessor(handler));
  shared_ptr serverTransport(new TServerSocket(port));
  shared_ptr transportFactory(new TBufferedTransportFactory());
  shared_ptr protocolFactory(new TBinaryProtocolFactory());

  TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
  server.serve();
  return 0;
}

Podemos ver que nos creo los métodos que le indicamos, aquí es donde definiremos que hacer cuando un cliente nos convoque, para este tutorial vamos a utilizar el método obtener posición. Primero definimos un arreglo de String, con diferentes nombres en cada posición, en el constructor del ejemplo.

Y luego en el método obtener posición, retornaremos lo que contenga el arreglo en la posición que solicitan. Así nos quedaría


#include 




// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.

#include "EjemploT.h"
#include 
#include 
#include 
#include 

using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;

using boost::shared_ptr;


class EjemploTHandler : virtual public EjemploTIf {
 public:
    std::string arreglo[10];
  EjemploTHandler() {
    // Your initialization goes here
      printf("se inicio\n");
      arreglo[0]="ALan";
      arreglo[1]="Beatriz";
      arreglo[2]="Carlos";
      arreglo[3]="Daniel";
      arreglo[4]="Elvis";
      arreglo[5]="Fer";
      arreglo[6]="Gustavo";
      arreglo[7]="Hillary";
      arreglo[8]="Isabel";
      arreglo[9]="Jose";
  }
  void ping() {
    // Your implementation goes here
    printf("ping\n");
  }

  void obtener_posicion(std::string& _return, const int32_t pos) {
    // Your implementation goes here
    printf("obtener_posicion %i\n",pos);

//    const char *cstr = str.c_str();
    if(pos<10 1="" _return="cstr;" a="" argc="" argv="" arreglo="" c="" c_str="" char="" const="" cstr="" delete="" dos="" else="" goes="" here="" implementation="" inicio="" int32_t="" int="" jemplothandler="" length="" main="" n="" port="7911;" pos="" printf="" qcoreapplication="" return="" shared_ptr="" strcpy="" sumar="" uno="" your=""> handler(new EjemploTHandler());
  shared_ptr processor(new EjemploTProcessor(handler));
  shared_ptr serverTransport(new TServerSocket(port));
  shared_ptr transportFactory(new TBufferedTransportFactory());
  shared_ptr protocolFactory(new TBinaryProtocolFactory());

  TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
  server.serve();

  return 0;
}



Pero si intentamos compilar, nos tirara un error, porque el compilador de g++ no encuentra las librerías de thrift.

Se necesitan agregar estas lineas al archivo .pro que utiliza QT para compilar thrift en c++.

QMAKE_CXXFLAGS += -std=c++0x -DHAVE_INTTYPES_H -DHAVE_NETINET_IN_H -Wall 

              INCLUDEPATH += -l/usr/local/include/thrift 
              LIBS += -L/usr/local/lib -lthrift


Y listo, ya tenemos nuestro servidor en c++.

Ahora con java
Así como creamos la carpeta con los archivos de c++, también creamos el archivo de java, en la carpeta gen-java, estará su clase en Java que genero thrift, posiblemente este entre varias carpetas dependiendo de namespace que definieron en el archivo thrift.

Vamos a crear un proyecto en NetBeans, y copiaremos la clase generada por thrift a la fuente de nuestro proyecto (Nombre_proyecto/src/nombre_paquetes/), para este ejemplo el proyecto se llamara EjemploThrift.

Ahora tenemos que implementar un cliente en este lado.
Siguiendo los tutoriales en la pagina oficial de Apache Thrift, lo crearemos en el método main de la siguiente manera
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package ejemplothrift;

import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;

/**
 *
 * @author alan
 */
public class EjemploThrift {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
            try {
            TSocket transport = new TSocket("localhost", 7911);
            transport.open();
            TProtocol protocol = new TBinaryProtocol(transport);

            EjemploT.Client client = new EjemploT.Client(protocol);

            //Llamada a un frame, donde estara la interacción con el usuario
            Frame1 f1=new Frame1();
            //Llamo al metodo setear, que solo sera para poder pasar al objeto cliente, y socket
            f1.setear(client,transport);
            f1.setVisible(true);
        } catch (TException e) {
            e.printStackTrace();
        }
    }
    
}


El código no tiene nada de extraordinario si se esta familiarizado con Java.
El programa en java consistirá en una serie de JLabel que al pasar al mouse encima mandara a pedir en C++, su posición equivalente en el arreglo que definimos y se desplegara en un JTextField. Por ejemplo, si pasa el mouse sobre el primer JLabel mandara a pedir la primer posición en el arreglo definido en C, y así sucesivamente. 

Incrusto los métodos solo para que tengan una idea mas clara de los métodos mencionados.
//metodo setear
//el cliente que se recibe aqui fue el creado en el main cuando se creo el socket
public void setear(EjemploT.Client client,TSocket transport){
        cliente=client;
        this.transport=transport;
}
//un metodo de la accion sobre un JLabel, todos los demas son iguales, solo cambia la posición que se manda a pedir
    private void jLabel1MouseEntered(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jLabel1MouseEntered
        try {            
            //aqui se utiliza el objeto cliente, y el método que definimos en el archivo thrift
            String result=cliente.obtener_posicion(0);
            jTextField1.setText(result);
        } catch (TException ex) {
            Logger.getLogger(Frame1.class.getName()).log(Level.SEVERE, null, ex);
        }
    }//GEN-LAST:event_jLabel1MouseEntered



Pero si compilamos este código en java tirara error, necesitamos agregar unas librerías al proyecto para que Netbeans pueda compilarlo.

¿Donde las conseguí? a prueba y error, pero el intento ganador fue crear un proyecto con maven, y editando el xml que genera el proyecto, siguiendo este  tutorial thrift.
Para agregarlas basta con dar click derecho en librerías, agregar Jar, y seleccionarlas.


Las librerías están junto con el código fuente en link del final.


 dejo un video con la demostración de todo ya funcionando

Comentarios

Entradas populares