Tuesday, November 6, 2012

Installing Thrift 0.9.0 with a Java server and a PHP client

Hi everyone,

Maybe it was the birthday hangover, maybe it was the fact that it was 2am, but I couldn't find a working "Hello World" for Thrift 0.9.0.

What I was trying to do, point-form styles:
  1. Run a java server with my business logic
  2. Interface with that fella in PHP
After some reading, I figured Thrift was definitely worth looking into.

Hopefully this save a few people some cranky moments! 

Step 1: download thrift.

This link should do the trick if you don't feel like compiling anything:
https://dist.apache.org/repos/dist/release/thrift/0.9.0/thrift-0.9.0.exe

Step 2: write your thrift file.

Mine looked like this.

1:  # time.thrift  
2:  namespace java com.myFirstServer.thrift  
3:  typedef i64 Timestamp  
4:  service TimeServer {  
5:    Timestamp time()  
6:  }  

Step 3: generate the PHP client code

 > thrift --gen php src\main\resources\server.thrift  

You'll end up with two files in this case:
  1. TimeServer.php
  2. Types.php
Step 4: generate the Java server code

 > thrift --gen java server.thrift  

This will have generated
  1. TimeServer.java
Step 5: write your server-side implementation

Essentially, this is where you code your implementation of the thrift file we wrote earlier.

1:  package com.myFirstServer.thrift;  
2:  import java.util.Date;  
3:  import org.apache.thrift.TException;  
4:  public class TimeServerImpl implements TimeServer.Iface  
5:  {  
6:    @Override  
7:    public long time() throws TException   
8:    {  
9:     return new Date().getTime();  
10:    }  
11:  }  

Step 5A: make sure you have your Maven dependencies setup:

 <dependency>  
  <groupId>org.apache.thrift</groupId>  
  <artifactId>libthrift</artifactId>  
  <version>0.9.0</version>  
 </dependency>  

Step 6: write your server's "main"

1:  package com.myFirstServer.server;  
2:  import org.apache.thrift.server.TServer;  
3:  import org.apache.thrift.server.TThreadPoolServer;  
4:  import org.apache.thrift.transport.TServerSocket;  
5:  import org.apache.thrift.transport.TTransportException;  
6:  import com.myFirstServer.thrift.TimeServer;  
7:  import com.myFirstServer.thrift.TimeServerImpl;  
8:  public class PriceServer  
9:  {  
10:    private void start() {  
11:     try {  
12:       TServerSocket serverTransport = new TServerSocket(7911);  
13:       TimeServer.Processor processor = new TimeServer.Processor (new TimeServerImpl());  
14:       TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor));  
15:       System.out.println("Starting server on port 7911 ...");  
16:       server.serve();  
17:     }   
18:     catch (TTransportException e)   
19:     {  
20:       e.printStackTrace();  
21:     }  
22:    }  
23:    public static void main(String[] args) {  
24:     PriceServer srv = new PriceServer();  
25:     srv.start();  
26:    }  
27:  }  

Easy-peazy.

Now begins the headache that was the PHP client side.

Seems that I starred at every permutation of these messages for the better part of an hour (I couldn't find a proper Thrift 0.9.0 tutorial... and it seem that things had changed enough to obsolete older tutorial):

 [Tue Nov 06 15:01:57 2012] [error] [client 192.168.1.125] PHP Warning: require_once(TimeServerClient.php): failed to open stream: No such file or directory in /home/erik/samba_share/ThriftTest.php on line 6  
 [Tue Nov 06 15:01:57 2012] [error] [client 192.168.1.125] PHP Fatal error: require_once(): Failed opening required 'TimeServerClient.php' (include_path='.:/usr/share/php:/usr/share/pear') in /home/erik/samba_share/ThriftTest.php on line 6  


Disclaimer: I'm very much a PHP newbie.

7. Download the Thrift PHP libs

Now, as opposed to what all the other tutorials tell you: you don't need to install, apt-get or build anything. All you need are the PHP libs that are packaged with Thrift, while trying to follow how-to's, I installed about a dozen dependencies on my linux machine for nothin'.

Let's say you end up untar-ing the bundle here "/home/erik/thrift-0.9.0", all you really care about will be "'/home/erik/thrift-0.9.0/lib/php/lib'".

Unless you insist on compiling the code generator, I don't feel you'll need anything BUT the PHP dependencies (which you will specify in the client code).

8. Write your client

I named it "ThriftTest.php"


1:  <?php   
2:  $GLOBALS['THRIFT_ROOT'] = '/home/erik/thrift-0.9.0/lib/php/lib';  
3:  /* Remember these two files? */  
4:  require_once 'Types.php';  
5:  require_once 'TimeServer.php';  
6:  /* Dependencies. In the proper order. */  
7:  require_once $GLOBALS['THRIFT_ROOT'].'/Thrift/Transport/TTransport.php';  
8:  require_once $GLOBALS['THRIFT_ROOT'].'/Thrift/Transport/TSocket.php';  
9:  require_once $GLOBALS['THRIFT_ROOT'].'/Thrift/Protocol/TProtocol.php';  
10:  require_once $GLOBALS['THRIFT_ROOT'].'/Thrift/Protocol/TBinaryProtocol.php';  
11:  require_once $GLOBALS['THRIFT_ROOT'].'/Thrift/Transport/TBufferedTransport.php';  
12:  require_once $GLOBALS['THRIFT_ROOT'].'/Thrift/Type/TMessageType.php';  
13:  require_once $GLOBALS['THRIFT_ROOT'].'/Thrift/Factory/TStringFuncFactory.php';  
14:  require_once $GLOBALS['THRIFT_ROOT'].'/Thrift/StringFunc/TStringFunc.php';  
15:  require_once $GLOBALS['THRIFT_ROOT'].'/Thrift/StringFunc/Core.php';  
16:  require_once $GLOBALS['THRIFT_ROOT'].'/Thrift/Type/TType.php';  
17:  use Thrift\Protocol\TBinaryProtocol;  
18:  use Thrift\Transport\TSocket;  
19:  use Thrift\Transport\TSocketPool;  
20:  use Thrift\Transport\TFramedTransport;  
21:  use Thrift\Transport\TBufferedTransport;  
22:  $host = '192.168.1.125';  
23:  $port = 7911;  
24:  $socket = new Thrift\Transport\TSocket($host, $port);  
25:  $transport = new TBufferedTransport($socket);  
26:  $protocol = new TBinaryProtocol($transport);  
27:  // Create a calculator client  
28:  $client = new TimeServerClient($protocol);  
29:  $transport->open();  
30:  echo "Time: " . $client -> time();  
31:  ?>  

And there you have it: launch the server...

 Starting server on port 7911 ...  

... and connect with your browser to your web server (http://192.168.1.199/ThriftTest.php)

Mission accomplished!


-Erik


Thank you to the following tutorials for getting me most of the way there:
http://nbonvin.wordpress.com/2009/03/08/simple-thrift-tutorial/
http://saladwithsteve.com/2008/04/my-first-thrift-app.html