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.
// 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; } </10>
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.
Geek de la tecnología, en busca de la mejora y aprendizaje continuo.
Ingeniero en ciencias de la computación, Postgrado en Análisis y predicción de datos