Cocoa Thrift binding patches from Andrew McGeachie

Summary: Latest updates to the Cocoa bindings


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665354 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/cocoa/src/TApplicationException.h b/lib/cocoa/src/TApplicationException.h
index 1fee06e..90831f4 100644
--- a/lib/cocoa/src/TApplicationException.h
+++ b/lib/cocoa/src/TApplicationException.h
@@ -17,6 +17,8 @@
 
 + (TApplicationException *) read: (id <TProtocol>) protocol;
 
+- (void) write: (id <TProtocol>) protocol;
+
 + (TApplicationException *) exceptionWithType: (int) type
                                        reason: (NSString *) message;
 
diff --git a/lib/cocoa/src/TApplicationException.m b/lib/cocoa/src/TApplicationException.m
index 1f658de..bace360 100644
--- a/lib/cocoa/src/TApplicationException.m
+++ b/lib/cocoa/src/TApplicationException.m
@@ -6,6 +6,8 @@
 - (id) initWithType: (int) type
              reason: (NSString *) reason
 {
+  mType = type;
+
   NSString * name;
   switch (type) {
   case TApplicationException_UNKNOWN_METHOD:
@@ -40,6 +42,8 @@
   int fieldType;
   int fieldID;
 
+  [protocol readStructBeginReturningName: NULL];
+
   while (true) {
     [protocol readFieldBeginReturningName: NULL
               type: &fieldType
@@ -74,6 +78,29 @@
 }
 
 
+- (void) write: (id <TProtocol>) protocol
+{
+  [protocol writeStructBeginWithName: @"TApplicationException"];
+
+  if ([self reason] != nil) {
+    [protocol writeFieldBeginWithName: @"message"
+                 type: TType_STRING
+                 fieldID: 1];
+    [protocol writeString: [self reason]];
+    [protocol writeFieldEnd];
+  }
+
+  [protocol writeFieldBeginWithName: @"type"
+               type: TType_I32
+               fieldID: 2];
+  [protocol writeI32: mType];
+  [protocol writeFieldEnd];
+
+  [protocol writeFieldStop];
+  [protocol writeStructEnd];
+}
+
+
 + (TApplicationException *) exceptionWithType: (int) type
                                       reason: (NSString *) reason
 {
diff --git a/lib/cocoa/src/protocol/TBinaryProtocol.h b/lib/cocoa/src/protocol/TBinaryProtocol.h
index 2c56740..7e288fa 100644
--- a/lib/cocoa/src/protocol/TBinaryProtocol.h
+++ b/lib/cocoa/src/protocol/TBinaryProtocol.h
@@ -7,6 +7,7 @@
   id <TTransport> mTransport;
   BOOL mStrictRead;
   BOOL mStrictWrite;
+  int32_t mMessageSizeLimit;
 }
 
 - (id) initWithTransport: (id <TTransport>) transport;
@@ -15,6 +16,9 @@
               strictRead: (BOOL) strictRead
              strictWrite: (BOOL) strictWrite;
 
+- (int32_t) messageSizeLimit;
+- (void) setMessageSizeLimit: (int32_t) sizeLimit;
+
 @end;
 
 
diff --git a/lib/cocoa/src/protocol/TBinaryProtocol.m b/lib/cocoa/src/protocol/TBinaryProtocol.m
index 19db55f..7564f5d 100644
--- a/lib/cocoa/src/protocol/TBinaryProtocol.m
+++ b/lib/cocoa/src/protocol/TBinaryProtocol.m
@@ -44,6 +44,18 @@
 }
 
 
+- (int32_t) messageSizeLimit
+{
+  return mMessageSizeLimit;
+}
+
+
+- (void) setMessageSizeLimit: (int32_t) sizeLimit
+{
+  mMessageSizeLimit = sizeLimit;
+}
+
+
 - (void) dealloc
 {
   [mTransport release];
@@ -70,7 +82,7 @@
                                   type: (int *) type
                             sequenceID: (int *) sequenceID
 {
-  int size = [self readI32];
+  int32_t size = [self readI32];
   if (size < 0) {
     int version = size & VERSION_MASK;
     if (version != VERSION_1) {
@@ -93,6 +105,12 @@
       @throw [TProtocolException exceptionWithName: @"TProtocolException"
                                  reason: @"Missing version in readMessageBegin, old client?"];
     }
+    if ([self messageSizeLimit] > 0 && size > [self messageSizeLimit]) {
+      @throw [TProtocolException exceptionWithName: @"TProtocolException"
+                                            reason: [NSString stringWithFormat: @"Message too big.  Size limit is: %d Message size is: %d",
+                                                     mMessageSizeLimit,
+                                                     size]];      
+    }
     NSString * messageName = [self readStringBody: size];
     if (name != NULL) {
       *name = messageName;
diff --git a/lib/cocoa/src/server/TSocketServer.m b/lib/cocoa/src/server/TSocketServer.m
index a65d017..d9d24e1 100644
--- a/lib/cocoa/src/server/TSocketServer.m
+++ b/lib/cocoa/src/server/TSocketServer.m
@@ -2,6 +2,7 @@
 #import "TSocketServer.h"
 #import "TNSFileHandleTransport.h"
 #import "TProtocol.h"
+#import "TTransportException.h"
 
 
 @implementation TSocketServer
@@ -17,19 +18,28 @@
   mProcessor = [processor retain];
   
   // create a socket
-  mServerSocket = [[NSSocketPort alloc] initWithTCPPort: 8081];
-  // wrap it in a file handle so we can get messages from it
-  mSocketFileHandle = [[NSFileHandle alloc] initWithFileDescriptor: [mServerSocket socket]
-                                            closeOnDealloc: YES];
+  mServerSocket = [[NSSocketPort alloc] initWithTCPPort: port];
+  // FIXME - move this separate start method and add method to close
+  // and cleanup any open ports
+  
+  if (mServerSocket == nil) {
+    NSLog(@"Unable to listen on TCP port %d", port);
+  } else {
+    NSLog(@"Listening on TCP port %d", port);
 
-  // register for notifications of accepted incoming connections
-  [[NSNotificationCenter defaultCenter] addObserver: self 
-                                        selector: @selector(connectionAccepted:) 
-                                        name: NSFileHandleConnectionAcceptedNotification
-                                        object: mSocketFileHandle];
-
-  // tell socket to listen
-  [mSocketFileHandle acceptConnectionInBackgroundAndNotify];
+    // wrap it in a file handle so we can get messages from it
+    mSocketFileHandle = [[NSFileHandle alloc] initWithFileDescriptor: [mServerSocket socket]
+                                                      closeOnDealloc: YES];
+    
+    // register for notifications of accepted incoming connections
+    [[NSNotificationCenter defaultCenter] addObserver: self 
+                                             selector: @selector(connectionAccepted:) 
+                                                 name: NSFileHandleConnectionAcceptedNotification
+                                               object: mSocketFileHandle];
+    
+    // tell socket to listen
+    [mSocketFileHandle acceptConnectionInBackgroundAndNotify];
+  }
   
   return self;
 }
@@ -45,7 +55,7 @@
 }
 
 
-- (void) connentionAccepted: (NSNotification *) aNotification
+- (void) connectionAccepted: (NSNotification *) aNotification
 {
   NSFileHandle * socket = [[aNotification userInfo] objectForKey: NSFileHandleNotificationFileHandleItem];
   
@@ -67,7 +77,12 @@
   id <TProtocol> inProtocol = [mInputProtocolFactory newProtocolOnTransport: transport];
   id <TProtocol> outProtocol = [mOutputProtocolFactory newProtocolOnTransport: transport];
   
-  while ([mProcessor processOnInputProtocol: inProtocol outputProtocol: outProtocol]);
+  @try {
+    while ([mProcessor processOnInputProtocol: inProtocol outputProtocol: outProtocol]);
+  }
+  @catch (TTransportException * te) {
+    NSLog(@"%@", te);
+  }
   
   [pool release];
 }
diff --git a/lib/cocoa/src/transport/THTTPClient.h b/lib/cocoa/src/transport/THTTPClient.h
index 98446cd..802ff51 100644
--- a/lib/cocoa/src/transport/THTTPClient.h
+++ b/lib/cocoa/src/transport/THTTPClient.h
@@ -14,5 +14,7 @@
 - (id) initWithURL: (NSURL *) aURL 
            timeout: (int) timeout;
 
+- (void) setURL: (NSURL *) aURL;
+
 @end
 
diff --git a/lib/cocoa/src/transport/THTTPClient.m b/lib/cocoa/src/transport/THTTPClient.m
index 45c0b80..2e31a98 100644
--- a/lib/cocoa/src/transport/THTTPClient.m
+++ b/lib/cocoa/src/transport/THTTPClient.m
@@ -3,11 +3,13 @@
 
 @implementation THTTPClient
 
-- (id) initWithURL: (NSURL *) aURL
-{
-  self = [super init];
-  mURL = [aURL retain];
 
+- (void) setupRequest
+{
+  if (mRequest != nil) {
+    [mRequest release];
+  }
+  
   // set up our request object that we'll use for each request
   mRequest = [[NSMutableURLRequest alloc] initWithURL: mURL];
   [mRequest setHTTPMethod: @"POST"];
@@ -15,6 +17,15 @@
   [mRequest setValue: @"application/x-thrift" forHTTPHeaderField: @"Accept"];
   [mRequest setValue: @"Cocoa/THTTPClient" forHTTPHeaderField: @"User-Agent"];
   [mRequest setCachePolicy: NSURLRequestReloadIgnoringCacheData];
+}
+
+
+- (id) initWithURL: (NSURL *) aURL
+{
+  self = [super init];
+  mURL = [aURL retain];
+
+  [self setupRequest];
 
   // create our request data buffer
   mRequestData = [[NSMutableData alloc] initWithCapacity: 1024];
@@ -34,6 +45,16 @@
 }
 
 
+- (void) setURL: (NSURL *) aURL
+{
+  [aURL retain];
+  [mURL release];
+  mURL = aURL;
+  
+  [self setupRequest];
+}
+
+
 - (void) dealloc
 {
   [mURL release];
diff --git a/lib/cocoa/src/transport/TNSFileHandleTransport.m b/lib/cocoa/src/transport/TNSFileHandleTransport.m
index 7ad1ba7..79a9e8d 100644
--- a/lib/cocoa/src/transport/TNSFileHandleTransport.m
+++ b/lib/cocoa/src/transport/TNSFileHandleTransport.m
@@ -1,5 +1,6 @@
 
 #import "TNSFileHandleTransport.h"
+#import "TTransportException.h"
 
 
 @implementation TNSFileHandleTransport
@@ -36,9 +37,8 @@
   while (got < len) {
     NSData * d = [mInputFileHandle readDataOfLength: len-got];
     if ([d length] == 0) {
-      @throw [NSException exceptionWithName: @"TTransportException"
-                                     reason: @"Cannot read. No more data."
-                                   userInfo: nil];
+      @throw [TTransportException exceptionWithName: @"TTransportException"
+                                  reason: @"Cannot read. No more data."];
     }
     [d getBytes: buf+got];
     got += [d length];
@@ -62,7 +62,7 @@
 
 - (void) flush
 {
-  [mOutputFileHandle synchronizeFile];  // ?
+
 }
 
 @end
diff --git a/lib/cocoa/src/transport/TNSStreamTransport.m b/lib/cocoa/src/transport/TNSStreamTransport.m
index 8130a8b..42a197e 100644
--- a/lib/cocoa/src/transport/TNSStreamTransport.m
+++ b/lib/cocoa/src/transport/TNSStreamTransport.m
@@ -1,4 +1,6 @@
 #import "TNSStreamTransport.h"
+#import "TTransportException.h"
+
 
 @implementation TNSStreamTransport
 
@@ -29,9 +31,7 @@
   while (got < len) {
     ret = [mInput read: buf+off+got maxLength: len-got];
     if (ret <= 0) {
-      @throw [NSException exceptionWithName: @"TTransportException"
-                          reason: @"Cannot read. Remote side has closed."
-                          userInfo: nil];
+      @throw [TTransportException exceptionWithReason: @"Cannot read. Remote side has closed."];
     }
     got += ret;
   }
@@ -39,23 +39,17 @@
 }
 
 
+// FIXME:geech:20071019 - make this write all
 - (void) write: (uint8_t *) data offset: (unsigned int) offset length: (unsigned int) length
 {
   int result = [mOutput write: data+offset maxLength: length];
   if (result == -1) {
-    NSDictionary * errorInfo = [NSDictionary dictionaryWithObject: [mOutput streamError]
-                                             forKey: @"error"];
-    @throw [NSException exceptionWithName: @"TTransportException"
-                        reason: [NSString stringWithFormat: @"Error writing to transport output stream (%@).", [mOutput streamError]]
-                                 userInfo: errorInfo];
+    @throw [TTransportException exceptionWithReason: @"Error writing to transport output stream."
+                                              error: [mOutput streamError]];
   } else if (result == 0) {
-    @throw [NSException exceptionWithName: @"TTransportException"
-                        reason: @"End of output stream."
-                        userInfo: nil];
+    @throw [TTransportException exceptionWithReason: @"End of output stream."];
   } else if (result != length) {
-    @throw [NSException exceptionWithName: @"TTransportException"
-                        reason: @"Output stream did not write all of our data."
-                        userInfo: nil];
+    @throw [TTransportException exceptionWithReason: @"Output stream did not write all of our data."];
   }
 } 
 
diff --git a/lib/cocoa/src/transport/TSocketClient.m b/lib/cocoa/src/transport/TSocketClient.m
index f3acc3b..e8ae6e9 100644
--- a/lib/cocoa/src/transport/TSocketClient.m
+++ b/lib/cocoa/src/transport/TSocketClient.m
@@ -14,7 +14,11 @@
             inputStream: &input 
             outputStream: &output];
 
-  return [super initWithInputStream: input outputStream: output];
+  self = [super initWithInputStream: input outputStream: output];
+  [input open];
+  [output open];
+  
+  return self;
 }
 
 
diff --git a/lib/cocoa/src/transport/TTransportException.h b/lib/cocoa/src/transport/TTransportException.h
index 5d3802b..7488ca5 100644
--- a/lib/cocoa/src/transport/TTransportException.h
+++ b/lib/cocoa/src/transport/TTransportException.h
@@ -3,4 +3,9 @@
 @interface TTransportException : TException {
 }
 
++ (id) exceptionWithReason: (NSString *) reason
+                     error: (NSError *) error;
+
++ (id) exceptionWithReason: (NSString *) reason;
+
 @end
diff --git a/lib/cocoa/src/transport/TTransportException.m b/lib/cocoa/src/transport/TTransportException.m
index e1102e2..3f82935 100644
--- a/lib/cocoa/src/transport/TTransportException.m
+++ b/lib/cocoa/src/transport/TTransportException.m
@@ -1,4 +1,24 @@
 #import "TTransportException.h"
 
 @implementation TTransportException
+
++ (id) exceptionWithReason: (NSString *) reason
+                     error: (NSError *) error
+{
+  NSDictionary * userInfo = nil;
+  if (error != nil) {
+    userInfo = [NSDictionary dictionaryWithObject: error forKey: @"error"];
+  }
+
+  return [super exceptionWithName: @"TTransportException"
+                           reason: reason
+                         userInfo: userInfo];
+}
+
+
++ (id) exceptionWithReason: (NSString *) reason
+{
+  return [self exceptionWithReason: reason error: nil];
+}
+
 @end