Apache Thrift - Cross Language Compatibility



Cross Language Compatibility in Thrift

Apache Thrift is designed to be cross-language compatible, enabling flawless communication between services written in different programming languages.

Apache Thrift provides a framework for defining data types and service interfaces in a language-independent manner. It then generates code in multiple programming languages, allowing services written in different languages to communicate effectively.

This feature is important for building distributed systems where different components may be implemented in different languages.

Defining Thrift IDL

The Thrift IDL allows you to define the data types and service methods in a language-independent way. This definition is then used to generate code in various programming languages.

Example

In the following example, a "User" struct and "UserService" service are defined. Thrift IDL abstracts these definitions so that they can be implemented in different languages −

namespace py example

struct User {
  1: string username,
  2: i32 age
}
service UserService {
  User getUser(1: string username),
  void updateUser(1: User user)
}

Generating Code for Different Languages

Thrift tools can generate source code in various languages from the IDL file. This process ensures that the data structures and service methods are consistent across different languages. Following are the steps to generate code −

  • Define Your IDL File: Create a ".thrift" file with your data structures and service definitions.
  • Generate Code for Target Languages: Use the Thrift compiler to generate source code in the desired languages.
  • Implement and Use Generated Code: Implement the service logic in the generated classes and use them in your application.

Generating Python Code

To generate Python code, use the Thrift compiler with the --gen option. This command creates a Python module containing classes and methods based on the IDL definitions −

thrift --gen py service.thrift

Generating Java Code

Similarly, you can generate Java code using the --gen option. This command creates a Java package with classes and methods based on the IDL definitions −

thrift --gen java service.thrift

Implementing the Service in Different Languages

With the generated code, you can now implement the service in different languages. We will walk through how to implement the ExampleService in both Python and Java.

Python Implementation

Following is the step-by-step explanation to implement the "ExampleService" in Python −

Import Necessary Modules:

  • TServer: For setting up the server.
  • TSocket, TTransport: For handling network communication.
  • TBinaryProtocol: For serialization of data.
  • ExampleService: The generated service interface.

Define the Service Handler:

  • Create a class "ExampleServiceHandler" that implements the "ExampleService.Iface" interface.
  • Implement the "sayHello" method to print a greeting message.

Set Up the Server:

  • Create instances for the handler and processor.
  • Set up the transport using "TSocket.TServerSocket" on port 9090.
  • Use buffered transport and binary protocol for communication.
  • Initialize the server with the transport, protocol, and handler.

Start the Server:

  • Print a message indicating the server is starting.
  • Call "server.serve()" to start listening for client requests.
from thrift.server import TServer
from thrift.transport import TSocket, TTransport
from thrift.protocol import TBinaryProtocol
from example import ExampleService

class ExampleServiceHandler(ExampleService.Iface):
   def sayHello(self, person):
      print(f"Hello {person.name}, age {person.age}")

handler = ExampleServiceHandler()
processor = ExampleService.Processor(handler)
transport = TSocket.TServerSocket(port=9090)
tfactory = TTransport.TBufferedTransportFactory()
pfactory = TBinaryProtocol.TBinaryProtocolFactory()

server = TServer.TSimpleServer(processor, transport, tfactory, pfactory)
print("Starting the Python server...")
server.serve()

In this example, we set up a simple Thrift server in Python that listens on port 9090. The "ExampleServiceHandler" handles incoming requests by implementing the "sayHello" method.

Java Implementation

Similarly, here we set up a simple Thrift server in Java that listens on port 9090. The "ExampleServiceHandler" handles incoming requests by implementing the "sayHello" method −

import example.ExampleService;
import example.Person;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TServerTransport;

public class ExampleServiceHandler implements ExampleService.Iface {
   @Override
   public void sayHello(Person person) throws TException {
      System.out.println("Hello " + person.getName() + ", age " + person.getAge());
   }

   public static void main(String[] args) {
      try {
         ExampleServiceHandler handler = new ExampleServiceHandler();
         ExampleService.Processor<ExampleServiceHandler> processor = new ExampleService.Processor<>(handler);
         TServerTransport serverTransport = new TServerSocket(9090);
         TBinaryProtocol.Factory protocolFactory = new TBinaryProtocol.Factory();
         TSimpleServer server = new TSimpleServer(new TServer.Args(serverTransport).processor(processor).protocolFactory(protocolFactory));
         System.out.println("Starting the Java server...");
         server.serve();
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}

Cross-Language Communication

With the services implemented in different languages, you can now test cross-language communication. This means you can have a client written in one language communicate with a server written in another language. Heres how it works −

  • Python Client Calling Java Service: Write a Python client that communicates with the Java server.
  • Java Client Calling Python Service: Write a Java client that communicates with the Python server.

Example: Python Client

Following is a Python client that connects to a Thrift service running on a Java server −

from thrift.transport import TSocket, TTransport
from thrift.protocol import TBinaryProtocol
from example import ExampleService

transport = TSocket.TSocket('localhost', 9090)
transport = TTransport.TBufferedTransport(transport)
protocol = TBinaryProtocol.TBinaryProtocol(transport)
client = ExampleService.Client(protocol)

transport.open()
person = ExampleService.Person(name="Alice", age=30)
client.sayHello(person)
transport.close()

Example: Java Client

Similarly, we write a Java client that communicates with a Thrift service running on a Python server −

import example.ExampleService;
import example.Person;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;

public class ExampleClient {
   public static void main(String[] args) {
      try {
         TTransport transport = new TSocket("localhost", 9090);
         TBinaryProtocol protocol = new TBinaryProtocol(transport);
         ExampleService.Client client = new ExampleService.Client(protocol);
         transport.open();
         Person person = new Person("Bob", 25);
         client.sayHello(person);
         transport.close();
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}
Advertisements