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

7 comments:

  1. This is exactly what i was looking for. Weird this is the first comment since you wrote it xD

    ReplyDelete
  2. Thanks for posting this! I was banging my head against the wall trying to use tutorials written against earlier versions of Thrift.

    You might want to require_once and use the exception classes. I'm still struggling to get all of my client code working when the server's not running.

    ReplyDelete
  3. Thank you so much! I was about to quit Thrift because of their terrible documentation/tutorial. Sir, you really saved my day!

    ReplyDelete
  4. I feel your pain: glad I could be of service!

    ReplyDelete
  5. Thanks so much!

    What I also like is that this doesn't use the Symfony FW or anything else for that matter, just plain old PHP and Thrift.

    I have to say while the Thrift project is great, their documentation is terrible!

    ReplyDelete
  6. This is the most helpful I've found on Thrift, their documentation was written as if they don't want anyone to understand it.
    I'm faced with such currently

    ReplyDelete