DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations

Apache Thrift Quickstart Tutorial

Buddhika  Chamith user avatar by
Buddhika Chamith
·
Feb. 09, 12 · Interview
Like (0)
Save
Tweet
Share
17.46K Views

Join the DZone community and get the full member experience.

Join For Free

Thrift is a cross language RPC framework initially developed at Facebook, now open sourced as an Apache project. This post will describe how to write a thrift service and client in different modes such as blocking, non blocking and asynchronous.

(I felt latter two modes are less documented and needed some tutorial type introduction, hence the motivation of this post). To easily follow the tutorial it’s beneficial that you have a basic understanding of Thrift architecture consisting of Transports, Protocols and Processors. (A good paper can be found at [1]). Here I will be using Thrift version 0.7 and Thrift’s Java binding.

Thrift Installation

Installation instructions can be found at http://wiki.apache.org/thrift/ThriftInstallation.

To sum up Ubuntu installation steps.

1. Install required dependencies.

     $ sudo apt-get install libboost-dev libboost-test-dev libboost-program-options-dev libevent-dev automake libtool flex bison pkg-config g++ libssl-dev

2. Go to the installation root directory.

3.  $ ./configure

4.  $ make

5. Become super user and

      $ make install

Now let’s get on with creating the service and consuming it.

Service Definition

Here a service with simple arithmetic operations is defined. Note the use of typedef directive to declare alternative names for base types i64 and i32. Add following in a file named  ‘arithmetic.thrift’.

namespace java tutorial.arithmetic.gen  // define namespace for java code

typedef i64 long
typedef i32 int
service ArithmeticService {  // defines simple arithmetic service
            long add(1:int num1, 2:int num2),
            long multiply(1:int num1, 2:int num2),
}

Code will be generated under ‘tutorial.arithmetic.gen’ package.

Now generate Java code using following command line.

$ thrift –gen java arithmetic.thrift

The source tutorial.arithmetic.gen.ArithmeticService.java will be generated.

Blocking Mode

Let’s create a blocking mode server and a client to consume the service.

First we need to implement the service using generated service skeleton. The interface to implement is ArithmeticService.Iface.

	public class ArithmeticServiceImpl implements ArithmeticService.Iface {
	 
	    public long add(int num1, int num2) throws TException {
	        return num1 + num2;
	    }
	 
	    public long multiply(int num1, int num2) throws TException {
	        return num1 * num2;
	    }
	 
	}

Now that being done let’s create the Thrift server which would server request for this service. Remember this is a blocking server so the server threads doing I/O will wait.

	public class Server {
	 
	    private void start() {
	        try {
	            TServerSocket serverTransport = new TServerSocket(7911);
	 
	            ArithmeticService.Processor processor = new ArithmeticService.Processor(new ArithmeticServiceImpl());
	 
	            TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).
	                    processor(processor));
	            System.out.println("Starting server on port 7911 ...");
	            server.serve();
	        } catch (TTransportException e) {
	            e.printStackTrace();
	        }
	    }
	 
	    public static void main(String[] args) {
	        Server srv = new Server();
	        srv.start();
	    }
	 
	}

Here TThreadPoolServer implementation is used which would utilize a thread pool to serve incoming requests.

Now let’s write the client.

public class ArithmeticClient {

    private void invoke() {
        TTransport transport;
        try {
            transport = new TSocket("localhost", 7911);

            TProtocol protocol = new TBinaryProtocol(transport);

            ArithmeticService.Client client = new ArithmeticService.Client(protocol);
            transport.open();

            long addResult = client.add(100, 200);
            System.out.println("Add result: " + addResult);
            long multiplyResult = client.multiply(20, 40);
            System.out.println("Multiply result: " + multiplyResult);

            transport.close();
        } catch (TTransportException e) {
            e.printStackTrace();
        } catch (TException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        ArithmeticClient c = new ArithmeticClient();
        c.invoke();

    }
}

TBinaryProtocol is used for encoding data transferred between server and client. Now start the server and invoke the service using client to results.

Non Blocking Mode

Now lets create a non blocking server which uses Java non blocking I/O underneath. We can use the same service implementation as before (ArithmeticServiceImpl).

public class NonblockingServer {

    private void start() {
        try {
            TNonblockingServerTransport serverTransport = new TNonblockingServerSocket(7911);
            ArithmeticService.Processor processor = new ArithmeticService.Processor(new ArithmeticServiceImpl());

            TServer server = new TNonblockingServer(new TNonblockingServer.Args(serverTransport).
                    processor(processor));
            System.out.println("Starting server on port 7911 ...");
            server.serve();
        } catch (TTransportException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        NonblockingServer srv = new NonblockingServer();
        srv.start();
    }
}

Here TNonblockingServerSocket is used which encapsulates a ServerSocketChannel.

Code for the non blocking client is as follows.

public class NonblockingClient {

    private void invoke() {
        TTransport transport;
        try {
            transport = new TFramedTransport(new TSocket("localhost", 7911));
            TProtocol protocol = new TBinaryProtocol(transport);

            ArithmeticService.Client client = new ArithmeticService.Client(protocol);
            transport.open();

            long addResult = client.add(100, 200);
            System.out.println("Add result: " + addResult);
            long multiplyResult = client.multiply(20, 40);
            System.out.println("Multiply result: " + multiplyResult);

            transport.close();
        } catch (TTransportException e) {
            e.printStackTrace();
        } catch (TException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        NonblockingClient c = new NonblockingClient();
        c.invoke();
    }

}

Note the usage of TFramedTransport wrapping normal TSocket transport. Non blocking server requires client to use TFramedTransport which would frame the data sent over the wire. Fire up the server and send a request using the client. You will see the same results as before, this time using non blocking mode.

Asynchronous Mode

We can write asynchronous clients to call a Thrift service. A callback needs to be registered which will get invoked at successful completion of the request. Blocking mode server didn’t work (method invocation returns with an empty response) with the asynchronous client (May be it’s because we are using TNonblockingSocket at the client side. See construction of ArithmeticService.AsyncClient. So this may be the proper behaviour). Non blocking mode  server seems to work without an issue. So you can use the non blocking server from earlier with the client shown below.

public class AsyncClient {

    private void invoke() {
        try {
            ArithmeticService.AsyncClient client = new ArithmeticService.
                    AsyncClient(new TBinaryProtocol.Factory(), new TAsyncClientManager(),
                                new TNonblockingSocket("localhost", 7911));

            client.add(200, 400, new AddMethodCallback());

            client = new ArithmeticService.
                    AsyncClient(new TBinaryProtocol.Factory(), new TAsyncClientManager(),
                                new TNonblockingSocket("localhost", 7911));
            client.multiply(20, 50, new MultiplyMethodCallback());

        } catch (TTransportException e) {
            e.printStackTrace();
        } catch (TException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        AsyncClient c = new AsyncClient();
        c.invoke();

    }

    class AddMethodCallback
            implements AsyncMethodCallback<ArithmeticService.AsyncClient.add_call> {

        public void onComplete(ArithmeticService.AsyncClient.add_call add_call) {
            try {
                long result = add_call.getResult();
                System.out.println("Add from server: " + result);
            } catch (TException e) {
                e.printStackTrace();
            }
        }

        public void onError(Exception e) {
            System.out.println("Error : ");
            e.printStackTrace();
        }

    }

    class MultiplyMethodCallback
            implements AsyncMethodCallback<ArithmeticService.AsyncClient.multiply_call> {

        public void onComplete(ArithmeticService.AsyncClient.multiply_call multiply_call) {
            try {
                long result = multiply_call.getResult();
                System.out.println("Multiply from server: " + result);
            } catch (TException e) {
                e.printStackTrace();
            }
        }

        public void onError(Exception e) {
            System.out.println("Error : ");
            e.printStackTrace();
        }

    }

}

 

Two callbacks have been defined corresponding to each operation of the service. Note the usage of two client instances for the two invocations. Each invocation needs a separate client instance or otherwise client will fail with following exception

“Exception in thread “main” java.lang.IllegalStateException: Client is currently executing another method: tutorial.arithmetic.gen.ArithmeticService$AsyncClient$add_call“

So this wraps up my quick start on Thrift with different modes of operation. Hope somebody may find this useful. For any suggestions or corrections do not hesitate to comment.

[1] http://thrift.apache.org/static/thrift-20070401.pdf

Source:  http://chamibuddhika.wordpress.com/2011/10/02/apache-thrift-quickstart-tutorial/

 

 

Thrift (protocol) Apache Thrift Blocking (computing)

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • How To Best Use Java Records as DTOs in Spring Boot 3
  • Asynchronous Messaging Service
  • What Are the Different Types of API Testing?
  • Journey to Event Driven, Part 1: Why Event-First Programming Changes Everything

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: