Various Thrift fixes, including Application Exception support in Ruby, better errror messages across languages, etc.

Reviewed By: thrift


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665058 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/cleanup.sh b/compiler/cpp/cleanup.sh
index 7dea388..e2ab8f8 100755
--- a/compiler/cpp/cleanup.sh
+++ b/compiler/cpp/cleanup.sh
@@ -1,5 +1,6 @@
 #!/bin/sh
 
+make clean 1>/dev/null 2>/dev/null
 rm -rf \
 AUTHORS \
 ChangeLog \
diff --git a/compiler/cpp/configure.ac b/compiler/cpp/configure.ac
index 5408146..f6aa0f5 100644
--- a/compiler/cpp/configure.ac
+++ b/compiler/cpp/configure.ac
@@ -44,4 +44,6 @@
 
 AC_PROG_LIBTOOL
 
+AC_PROG_MAKE_SET
+
 AC_OUTPUT(Makefile)
diff --git a/compiler/cpp/src/generate/t_rb_generator.cc b/compiler/cpp/src/generate/t_rb_generator.cc
index 7672030..6e29352 100644
--- a/compiler/cpp/src/generate/t_rb_generator.cc
+++ b/compiler/cpp/src/generate/t_rb_generator.cc
@@ -705,12 +705,18 @@
         indent() << "def " << function_signature(&recv_function) << endl;
       indent_up();
 
-      f_service_ <<
-        indent() << "fname, mtype, rseqid = @iprot.readMessageBegin()" << endl;
-
       // TODO(mcslee): Validate message reply here, seq ids etc.
 
       f_service_ <<
+        indent() << "fname, mtype, rseqid = @iprot.readMessageBegin()" << endl <<
+        indent() << "if mtype == TMessageType::EXCEPTION" << endl <<
+        indent() << "  x = TApplicationException.new()" << endl <<
+        indent() << "  x.read(@iprot)" << endl <<
+        indent() << "  @iprot.readMessageEnd()" << endl <<
+        indent() << "  raise x" << endl <<
+        indent() << "end" << endl;
+
+      f_service_ <<
         indent() << "result = " << resultname << ".new()" << endl <<
         indent() << "result.read(@iprot)" << endl <<
         indent() << "@iprot.readMessageEnd()" << endl;
@@ -739,7 +745,7 @@
           "return" << endl;
       } else {
         f_service_ <<
-          indent() << "raise StandardError.new('" << (*f_iter)->get_name() << " failed: unknown result')" << endl;
+          indent() << "raise TApplicationException.new(TApplicationException::MISSING_RESULT, '" << (*f_iter)->get_name() << " failed: unknown result')" << endl;
       }     
 
       // Close function
@@ -812,7 +818,14 @@
     indent() << "if (@processMap.has_key?(name))" << endl <<
     indent() << "  @processMap[name].call(seqid, iprot, oprot)" << endl <<
     indent() << "else" << endl <<
-    indent() << "  print \"Unknown function #{name}\"" << endl <<
+    indent() << "  iprot.skip(TType::STRUCT)" << endl <<
+    indent() << "  iprot.readMessageEnd()" << endl <<
+    indent() << "  x = TApplicationException.new(TApplicationException::UNKNOWN_METHOD, 'Unknown function '+name)" << endl <<
+    indent() << "  oprot.writeMessageBegin(name, TMessageType::EXCEPTION, seqid)" << endl <<
+    indent() << "  x.write(oprot)" << endl <<
+    indent() << "  oprot.writeMessageEnd()" << endl <<
+    indent() << "  oprot.trans.flush()" << endl <<
+    indent() << "  return" << endl <<
     indent() << "end" << endl;
 
   // Read end of args field, the T_STOP, and the struct close
diff --git a/lib/php/src/transport/TPhpStream.php b/lib/php/src/transport/TPhpStream.php
index 8a4fb0a..03837a8 100644
--- a/lib/php/src/transport/TPhpStream.php
+++ b/lib/php/src/transport/TPhpStream.php
@@ -40,13 +40,13 @@
     if ($this->read_) {
       $this->inStream_ = @fopen('php://input', 'r');
       if (!is_resource($this->inStream_)) {
-        throw new Exception('TPhpStream: Could not open php://input');
+        throw new TException('TPhpStream: Could not open php://input');
       }
     }
     if ($this->write_) {
       $this->outStream_ = @fopen('php://output', 'w');
       if (!is_resource($this->outStream_)) {
-        throw new Exception('TPhpStream: Could not open php://output');
+        throw new TException('TPhpStream: Could not open php://output');
       }
     }
   }
@@ -71,7 +71,7 @@
   public function read($len) {
     $data = @fread($this->inStream_, $len);
     if (!$data) {
-      throw new Exception('TPhpStream: Could not read '.$len.' bytes');
+      throw new TException('TPhpStream: Could not read '.$len.' bytes');
     }
     return $data;
   }
@@ -80,7 +80,7 @@
     while (strlen($buf) > 0) {
       $got = @fwrite($this->outStream_, $buf);
       if ($got === 0 || $got === FALSE) {
-        throw new Exception('TPhpStream: Could not write '.strlen($buf).' bytes');
+        throw new TException('TPhpStream: Could not write '.strlen($buf).' bytes');
       }
       $buf = substr($buf, $got);
     }
diff --git a/lib/php/src/transport/TSocket.php b/lib/php/src/transport/TSocket.php
index 1600b6f..cce3a44 100644
--- a/lib/php/src/transport/TSocket.php
+++ b/lib/php/src/transport/TSocket.php
@@ -160,7 +160,7 @@
       if ($this->debug_) {
         call_user_func($this->debugHandler_, $error);
       }
-      throw new Exception($error);
+      throw new TException($error);
     }
     
     stream_set_timeout($this->handle_, 0, $this->sendTimeout_*1000);
@@ -197,17 +197,17 @@
       if ($buf === FALSE || $buf === '') {
         $md = stream_get_meta_data($this->handle_);
         if ($md['timed_out']) {
-          throw new Exception('TSocket: timed out reading '.$len.' bytes from '.
-                              $this->host_.':'.$this->port_);
+          throw new TException('TSocket: timed out reading '.$len.' bytes from '.
+                               $this->host_.':'.$this->port_);
         } else {
-          throw new Exception('TSocket: Could not read '.$len.' bytes from '.
-                              $this->host_.':'.$this->port_);
+          throw new TException('TSocket: Could not read '.$len.' bytes from '.
+                               $this->host_.':'.$this->port_);
         }
       } else if (($sz = strlen($buf)) < $len) {
         $md = stream_get_meta_data($this->handle_);
         if ($md['timed_out']) {
-          throw new Exception('TSocket: timed out reading '.$len.' bytes from '.
-                              $this->host_.':'.$this->port_);
+          throw new TException('TSocket: timed out reading '.$len.' bytes from '.
+                               $this->host_.':'.$this->port_);
         } else {
           $pre .= $buf;
           $len -= $sz;
@@ -233,11 +233,11 @@
     if ($data === FALSE || $data === '') {
       $md = stream_get_meta_data($this->handle_);
       if ($md['timed_out']) {
-        throw new Exception('TSocket: timed out reading '.$len.' bytes from '.
-                            $this->host_.':'.$this->port_);
+        throw new TException('TSocket: timed out reading '.$len.' bytes from '.
+                             $this->host_.':'.$this->port_);
       } else {
-        throw new Exception('TSocket: Could not read '.$len.' bytes from '.
-                            $this->host_.':'.$this->port_);
+        throw new TException('TSocket: Could not read '.$len.' bytes from '.
+                             $this->host_.':'.$this->port_);
       }
     }
     return $data;
@@ -258,11 +258,11 @@
       if ($got === 0 || $got === FALSE) {
         $md = stream_get_meta_data($this->handle_);
         if ($md['timed_out']) {
-          throw new Exception('TSocket: timed out writing '.$len.' bytes from '.
-                              $this->host_.':'.$this->port_);
+          throw new TException('TSocket: timed out writing '.$len.' bytes from '.
+                               $this->host_.':'.$this->port_);
         } else {
-            throw new Exception('TSocket: Could not write '.strlen($buf).' bytes '.
-                                $this->host_.':'.$this->port_);
+            throw new TException('TSocket: Could not write '.strlen($buf).' bytes '.
+                                 $this->host_.':'.$this->port_);
         }
       }
       $buf = substr($buf, $got);
@@ -275,8 +275,8 @@
   public function flush() {
     $ret = fflush($this->handle_);
     if ($ret === FALSE) {
-      throw new Exception('TSocket: Could not flush: '.
-                          $this->host_.':'.$this->port_);
+      throw new TException('TSocket: Could not flush: '.
+                           $this->host_.':'.$this->port_);
     }
   }
 }
diff --git a/lib/php/src/transport/TSocketPool.php b/lib/php/src/transport/TSocketPool.php
index 9e5ebcd..b3efb2d 100644
--- a/lib/php/src/transport/TSocketPool.php
+++ b/lib/php/src/transport/TSocketPool.php
@@ -221,7 +221,7 @@
             // Successful connection, return now
             return;
 
-          } catch (Exception $x) {
+          } catch (TException $tx) {
             // Connection failed
           }
         }
@@ -268,7 +268,7 @@
     if ($this->debug_) {
       call_user_func($this->debugHandler_, $error);
     }
-    throw new Exception($error);
+    throw new TException($error);
   }
 }
 
diff --git a/lib/py/src/Thrift.py b/lib/py/src/Thrift.py
index a1ec6cc..aeca9b9 100644
--- a/lib/py/src/Thrift.py
+++ b/lib/py/src/Thrift.py
@@ -43,6 +43,7 @@
 
   def __init__(self, message=None):
     Exception.__init__(self, message)
+    self.message = message
 
 class TApplicationException(TException):
 
diff --git a/lib/py/src/transport/TSocket.py b/lib/py/src/transport/TSocket.py
index 1f9c480..280d6aa 100644
--- a/lib/py/src/transport/TSocket.py
+++ b/lib/py/src/transport/TSocket.py
@@ -13,7 +13,6 @@
 
   """Socket implementation of TTransport base."""
 
-
   def __init__(self, host='localhost', port=9090):
     self.host = host
     self.port = port
@@ -34,7 +33,7 @@
       self.handle = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
       self.handle.connect((self.host, self.port))
     except socket.error, e:
-      raise TTransportException(TTransportException.NOT_OPEN)
+      raise TTransportException(TTransportException.NOT_OPEN, 'Could not connect to %s:%d' % (self.host, self.port))
 
   def close(self):
     if self.handle != None:
diff --git a/lib/py/src/transport/TTransport.py b/lib/py/src/transport/TTransport.py
index b655b32..305c10b 100644
--- a/lib/py/src/transport/TTransport.py
+++ b/lib/py/src/transport/TTransport.py
@@ -14,11 +14,11 @@
 
   """Custom Transport Exception class"""
 
-  UNKNOWN = 0,
-  NOT_OPEN = 1,
-  ALREADY_OPEN = 2,
-  TIMED_OUT = 3,
-  END_OF_FILE = 4,
+  UNKNOWN = 0
+  NOT_OPEN = 1
+  ALREADY_OPEN = 2
+  TIMED_OUT = 3
+  END_OF_FILE = 4
 
   def __init__(self, type=UNKNOWN, message=None):
     TException.__init__(self, message)
diff --git a/lib/rb/lib/thrift/protocol/tprotocol.rb b/lib/rb/lib/thrift/protocol/tprotocol.rb
index 4376024..3c13b4b 100644
--- a/lib/rb/lib/thrift/protocol/tprotocol.rb
+++ b/lib/rb/lib/thrift/protocol/tprotocol.rb
@@ -8,26 +8,8 @@
 #
 # Author: Mark Slee <mcslee@facebook.com>
 #
-class TType
-  STOP = 0
-  VOID = 1
-  BOOL = 2
-  BYTE = 3
-  DOUBLE = 4
-  I16 = 6
-  I32 = 8
-  I64 = 10
-  STRING = 11
-  STRUCT = 12
-  MAP = 13
-  SET = 14
-  LIST = 15
-end
 
-class TMessageType
-  CALL = 1
-  REPLY = 2
-end
+require 'thrift/thrift'
 
 class TProtocol
   
diff --git a/lib/rb/lib/thrift/thrift.rb b/lib/rb/lib/thrift/thrift.rb
index 16c7174..2b9ebbb 100644
--- a/lib/rb/lib/thrift/thrift.rb
+++ b/lib/rb/lib/thrift/thrift.rb
@@ -8,6 +8,99 @@
 #
 # Author: Mark Slee <mcslee@facebook.com>
 #
+
+class TType
+  STOP = 0
+  VOID = 1
+  BOOL = 2
+  BYTE = 3
+  DOUBLE = 4
+  I16 = 6
+  I32 = 8
+  I64 = 10
+  STRING = 11
+  STRUCT = 12
+  MAP = 13
+  SET = 14
+  LIST = 15
+end
+
+class TMessageType
+  CALL = 1
+  REPLY = 2
+  EXCEPTION = 3
+end
+
 module TProcessor
   def process(iprot, oprot); nil; end
 end
+
+class TException < StandardError
+  def initialize(message)
+    super(message)
+    @message = message
+  end
+
+  attr_reader :message
+end
+
+class TApplicationException < TException
+
+  UNKNOWN = 0
+  UNKNOWN_METHOD = 1
+  INVALID_MESSAGE_TYPE = 2
+  WRONG_METHOD_NAME = 3
+  BAD_SEQUENCE_ID = 4
+  MISSING_RESULT = 5
+  
+  attr_reader :type
+
+  def initialize(type=UNKNOWN, message=nil)
+    super(message)
+    @type = type
+  end
+
+  def read(iprot)
+    iprot.readStructBegin()
+    while true
+      fname, ftype, fid = iprot.readFieldBegin()
+      if (ftype === TType::STOP)
+        break
+      end
+      if (fid == 1)
+        if (ftype === TType::STRING)
+          @message = iprot.readString();
+        else
+          iprot.skip(ftype)
+        end
+      elsif (fid == 2)
+        if (ftype === TType::I32)
+          @type = iprot.readI32();
+        else
+          iprot.skip(ftype)
+        end
+      else
+        iprot.skip(ftype)
+      end
+      iprot.readFieldEnd()
+    end
+    iprot.readStructEnd()
+  end
+
+  def write(oprot)
+    oprot.writeStructBegin('TApplicationException')
+    if (@message != nil)
+      oprot.writeFieldBegin('message', TType::STRING, 1)
+      oprot.writeString(@message)
+      oprot.writeFieldEnd()
+    end
+    if (@type != nil)
+      oprot.writeFieldBegin('type', TType::I32, 2)
+      oprot.writeI32(@type)
+      oprot.writeFieldEnd()
+    end
+    oprot.writeFieldStop()
+    oprot.writeStructEnd()
+  end
+
+end
diff --git a/lib/rb/lib/thrift/transport/tsocket.rb b/lib/rb/lib/thrift/transport/tsocket.rb
index d2e197f..9de2b8e 100644
--- a/lib/rb/lib/thrift/transport/tsocket.rb
+++ b/lib/rb/lib/thrift/transport/tsocket.rb
@@ -23,7 +23,11 @@
   end
 
   def open()
-    @handle = TCPSocket.new(@host, @port)
+    begin
+      @handle = TCPSocket.new(@host, @port)
+    rescue StandardError
+      raise TTransportException.new(TTransportException::NOT_OPEN, "Could not connect to #{@host}:#{@port}")
+    end
   end
 
   def isOpen()
@@ -31,15 +35,23 @@
   end
   
   def write(str)
-    @handle.write(str)
+    begin
+      @handle.write(str)
+    rescue StandardError
+      raise TTransportException.new(TTransportException::NOT_OPEN)
+    end
   end
 
   def read(sz)
-    data = @handle.recv(sz)
-    if (data.length == 0)
-      raise TTransportException.new("TSocket: Could not read #{sz} bytes from #{@host}:#{@port}")
+    begin
+      data = @handle.recv(sz)
+      if (data.length == 0)
+        raise TTransportException.new("TSocket: Could not read #{sz} bytes from #{@host}:#{@port}")
+      end
+      return data
+    rescue StandardError
+      raise TTransportException.new(TTransportException::NOT_OPEN)
     end
-    return data
   end
 
   def close()
diff --git a/lib/rb/lib/thrift/transport/ttransport.rb b/lib/rb/lib/thrift/transport/ttransport.rb
index 92c606a..5b9b8b1 100644
--- a/lib/rb/lib/thrift/transport/ttransport.rb
+++ b/lib/rb/lib/thrift/transport/ttransport.rb
@@ -8,10 +8,24 @@
 #
 # Author: Mark Slee <mcslee@facebook.com>
 #
-class TTransportException < StandardError
-  def initialize(message)
+
+require 'thrift/thrift'
+
+class TTransportException < TException
+
+  UNKNOWN = 0
+  NOT_OPEN = 1
+  ALREADY_OPEN = 2
+  TIMED_OUT = 3
+  END_OF_FILE = 4
+
+  attr_reader :type
+
+  def initialize(type=UNKNOWN, message=nil)
     super(message)
-  end 
+    @type = type
+  end
+
 end
 
 class TTransport
@@ -54,5 +68,42 @@
     return trans
   end
 end
+  
+class TBufferedTransport < TTransport
+  def initialize(transport)
+    @transport = transport
+    @wbuf = ''
+  end
+  
+  def isOpen()
+    return @transport.isOpen()
+  end
 
-    
+  def open()
+    @transport.open()
+  end
+
+  def close()
+    @transport.close()
+  end
+  
+  def read(sz)
+    return @transport.read(sz)
+  end
+  
+  def write(buf)
+    @wbuf += buf
+  end
+
+  def flush()
+    @transport.write(@wbuf)
+    @transport.flush()
+    @wbuf = ''
+  end
+end
+
+class TBufferedTransportFactory < TTransportFactory
+  def getTransport(transport)
+    return TBufferedTransport.new(transport)
+  end
+end
diff --git a/tutorial/php/PhpClient.php b/tutorial/php/PhpClient.php
index ca4f50d..fdd12ac 100755
--- a/tutorial/php/PhpClient.php
+++ b/tutorial/php/PhpClient.php
@@ -24,41 +24,46 @@
 require_once $GEN_DIR.'/tutorial_types.php';
 error_reporting(E_ALL);
 
-$socket = new TSocket('localhost', 9090);
-$transport = new TBufferedTransport($socket, 1024, 1024);
-$protocol = new TBinaryProtocol($transport);
-$client = new CalculatorClient($protocol);
-
-$transport->open();
-
-$client->ping();
-print "ping()\n";
-
-$sum = $client->add(1,1);
-print "1+1=$sum\n";
-
-$work = new tutorial_Work();
-
-$work->op = tutorial_Operation::DIVIDE;
-$work->num1 = 1;
-$work->num2 = 0;
-
 try {
-  $client->calculate(1, $work);
-  print "Whoa! We can divide by zero?\n";
-} catch (tutorial_InvalidOperation $io) {
-  print "InvalidOperation: $io->why\n";
+  $socket = new TSocket('localhost', 9090);
+  $transport = new TBufferedTransport($socket, 1024, 1024);
+  $protocol = new TBinaryProtocol($transport);
+  $client = new CalculatorClient($protocol);
+  
+  $transport->open();
+  
+  $client->ping();
+  print "ping()\n";
+ 
+  $sum = $client->add(1,1);
+  print "1+1=$sum\n";
+  
+  $work = new tutorial_Work();
+  
+  $work->op = tutorial_Operation::DIVIDE;
+  $work->num1 = 1;
+  $work->num2 = 0;
+
+  try {
+    $client->calculate(1, $work);
+    print "Whoa! We can divide by zero?\n";
+  } catch (tutorial_InvalidOperation $io) {
+    print "InvalidOperation: $io->why\n";
+  }
+  
+  $work->op = tutorial_Operation::SUBTRACT;
+  $work->num1 = 15;
+  $work->num2 = 10;
+  $diff = $client->calculate(1, $work);
+  print "15-10=$diff\n";
+  
+  $log = $client->getStruct(1);
+  print "Log: $log->value\n";
+  
+  $transport->close();
+  
+} catch (TException $tx) {
+  print 'TException: '.$tx->getMessage()."\n";
 }
 
-$work->op = tutorial_Operation::SUBTRACT;
-$work->num1 = 15;
-$work->num2 = 10;
-$diff = $client->calculate(1, $work);
-print "15-10=$diff\n";
-
-$log = $client->getStruct(1);
-print "Log: $log->value\n";
-
-$transport->close();
-
 ?>
diff --git a/tutorial/py/PythonClient.py b/tutorial/py/PythonClient.py
index 96ca03a..9dcecd9 100755
--- a/tutorial/py/PythonClient.py
+++ b/tutorial/py/PythonClient.py
@@ -6,53 +6,58 @@
 from tutorial import Calculator
 from tutorial.ttypes import *
 
+from thrift import Thrift
 from thrift.transport import TSocket
 from thrift.transport import TTransport
 from thrift.protocol import TBinaryProtocol
 
-# Make socket
-transport = TSocket.TSocket('localhost', 9090)
-
-# Buffering is critical. Raw sockets are very slow
-transport = TTransport.TBufferedTransport(transport)
-
-# Wrap in a protocol
-protocol = TBinaryProtocol.TBinaryProtocol(transport)
-
-# Create a client to use the protocol encoder
-client = Calculator.Client(protocol)
-
-# Connect!
-transport.open()
-
-client.ping()
-print 'ping()'
-
-sum = client.add(1,1)
-print '1+1=%d' % (sum)
-
-work = Work()
-
-work.op = Operation.DIVIDE
-work.num1 = 1
-work.num2 = 0
-
 try:
-  quotient = client.calculate(1, work)
-  print 'Whoa? You know how to divide by zero?'
-except InvalidOperation, io:
-  print 'InvalidOperation: %s' % (io.__str__())
 
-work.op = Operation.SUBTRACT
-work.num1 = 15
-work.num2 = 10
+  # Make socket
+  transport = TSocket.TSocket('localhost', 9090)
 
-diff = client.calculate(1, work)
-print '15-10=%d' % (diff)
+  # Buffering is critical. Raw sockets are very slow
+  transport = TTransport.TBufferedTransport(transport)
 
-log = client.getStruct(1)
-print 'Check log: %s' % (log.value)
+  # Wrap in a protocol
+  protocol = TBinaryProtocol.TBinaryProtocol(transport)
 
-# Close!
-transport.close()
+  # Create a client to use the protocol encoder
+  client = Calculator.Client(protocol)
 
+  # Connect!
+  transport.open()
+
+  client.ping()
+  print 'ping()'
+
+  sum = client.add(1,1)
+  print '1+1=%d' % (sum)
+
+  work = Work()
+  
+  work.op = Operation.DIVIDE
+  work.num1 = 1
+  work.num2 = 0
+
+  try:
+    quotient = client.calculate(1, work)
+    print 'Whoa? You know how to divide by zero?'
+  except InvalidOperation, io:
+    print 'InvalidOperation: %s' % (io.__str__())
+    
+  work.op = Operation.SUBTRACT
+  work.num1 = 15
+  work.num2 = 10
+    
+  diff = client.calculate(1, work)
+  print '15-10=%d' % (diff)
+
+  log = client.getStruct(1)
+  print 'Check log: %s' % (log.value)
+
+  # Close!
+  transport.close()
+
+except Thrift.TException, tx:
+  print '%s' % (tx.message)
diff --git a/tutorial/rb/RubyClient.rb b/tutorial/rb/RubyClient.rb
index e0b47b6..bcf1300 100755
--- a/tutorial/rb/RubyClient.rb
+++ b/tutorial/rb/RubyClient.rb
@@ -7,37 +7,43 @@
 
 require 'Calculator'
 
-transport = TSocket.new('localhost', 9090)
-protocol = TBinaryProtocol.new(transport)
-client = Calculator::Client.new(protocol)
-
-transport.open()
-
-client.ping()
-print "ping()\n"
-
-sum = client.add(1,1)
-print "1+1=", sum, "\n"
-
-work = Work.new()
-
 begin
-  work.op = Operation::DIVIDE
-  work.num1 = 1
-  work.num2 = 0
-  quot = client.calculate(1, work)
-  puts "Whoa, we can divide by 0 now?"
-rescue InvalidOperation => io
-  print "InvalidOperation: ", io.why, "\n"
+  
+  transport = TBufferedTransport.new(TSocket.new('localhost', 9090))
+  protocol = TBinaryProtocol.new(transport)
+  client = Calculator::Client.new(protocol)
+  
+  transport.open()
+  
+  client.ping()
+  print "ping()\n"
+  
+  sum = client.add(1,1)
+  print "1+1=", sum, "\n"
+  
+  work = Work.new()
+  
+  begin
+    work.op = Operation::DIVIDE
+    work.num1 = 1
+    work.num2 = 0
+    quot = client.calculate(1, work)
+    puts "Whoa, we can divide by 0 now?"
+  rescue InvalidOperation => io
+    print "InvalidOperation: ", io.why, "\n"
+  end
+  
+  work.op = Operation::SUBTRACT
+  work.num1 = 15
+  work.num2 = 10
+  diff = client.calculate(1, work)
+  print "15-10=", diff, "\n"
+  
+  log = client.getStruct(1)
+  print "Log: ", log.value, "\n"
+  
+  transport.close()
+
+rescue TException => tx
+  print 'TException: ', tx.message, "\n"
 end
-
-work.op = Operation::SUBTRACT
-work.num1 = 15
-work.num2 = 10
-diff = client.calculate(1, work)
-print "15-10=", diff, "\n"
-
-log = client.getStruct(1)
-print "Log: ", log.value, "\n"
-
-transport.close()
diff --git a/tutorial/rb/RubyServer.rb b/tutorial/rb/RubyServer.rb
index 2e9145d..ea39e15 100755
--- a/tutorial/rb/RubyServer.rb
+++ b/tutorial/rb/RubyServer.rb
@@ -71,7 +71,8 @@
 handler = CalculatorHandler.new()
 processor = Calculator::Processor.new(handler)
 transport = TServerSocket.new(9090)
-server = TSimpleServer.new(processor, transport)
+transportFactory = TBufferedTransportFactory.new()
+server = TSimpleServer.new(processor, transport, transportFactory)
 
 puts "Starting the server..."
 server.serve()