THRIFT-2905 Cocoa compiler should have option to produce "modern" Objective-C
Client: Cocoa (ObjectiveC & Swift)
Author: Kevin Wooten <kevin@wooten.com>

This closes #539
diff --git a/lib/cocoa/src/server/TSocketServer.m b/lib/cocoa/src/server/TSocketServer.m
index 07bc829..ccbbba1 100644
--- a/lib/cocoa/src/server/TSocketServer.m
+++ b/lib/cocoa/src/server/TSocketServer.m
@@ -21,37 +21,51 @@
 #import "TSocketServer.h"
 #import "TNSFileHandleTransport.h"
 #import "TProtocol.h"
-#import "TTransportException.h"
-#import "TObjective-C.h"
+#import "TTransportError.h"
+
 #import <sys/socket.h>
 #include <netinet/in.h>
 
 
 
-NSString * const kTSocketServer_ClientConnectionFinishedForProcessorNotification = @"TSocketServer_ClientConnectionFinishedForProcessorNotification";
-NSString * const kTSocketServer_ProcessorKey = @"TSocketServer_Processor";
-NSString * const kTSockerServer_TransportKey = @"TSockerServer_Transport";
+NSString *const TSocketServerClientConnectionFinished = @"TSocketServerClientConnectionFinished";
+NSString *const TSocketServerProcessorKey = @"TSocketServerProcessor";
+NSString *const TSockerServerTransportKey = @"TSockerServerTransport";
+
+
+@interface TSocketServer ()
+
+@property(strong, nonatomic) id<TProtocolFactory> inputProtocolFactory;
+@property(strong, nonatomic) id<TProtocolFactory> outputProtocolFactory;
+@property(strong, nonatomic) id<TProcessorFactory> processorFactory;
+@property(strong, nonatomic) NSFileHandle *socketFileHandle;
+@property(strong, nonatomic) dispatch_queue_t processingQueue;
+
+@end
 
 
 @implementation TSocketServer
 
-- (id) initWithPort: (int) port
-    protocolFactory: (id <TProtocolFactory>) protocolFactory
-   processorFactory: (id <TProcessorFactory>) processorFactory
+-(instancetype) initWithPort:(int)port
+             protocolFactory:(id <TProtocolFactory>)protocolFactory
+            processorFactory:(id <TProcessorFactory>)processorFactory;
 {
   self = [super init];
 
-  mInputProtocolFactory = [protocolFactory retain_stub];
-  mOutputProtocolFactory = [protocolFactory retain_stub];
-  mProcessorFactory = [processorFactory retain_stub];
+  _inputProtocolFactory = protocolFactory;
+  _outputProtocolFactory = protocolFactory;
+  _processorFactory = processorFactory;
+
+  dispatch_queue_attr_t processingQueueAttr =
+    dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_BACKGROUND, 0);
+
+  _processingQueue = dispatch_queue_create("TSocketServer.processing", processingQueueAttr);
 
   // create a socket.
   int fd = -1;
   CFSocketRef socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL);
   if (socket) {
-    CFOptionFlags flagsToClear = kCFSocketCloseOnInvalidate;
-    CFSocketSetSocketFlags(socket,  CFSocketGetSocketFlags(socket) & ~flagsToClear);
-
+    CFSocketSetSocketFlags(socket, CFSocketGetSocketFlags(socket) & ~kCFSocketCloseOnInvalidate);
     fd = CFSocketGetNative(socket);
     int yes = 1;
     setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
@@ -63,135 +77,88 @@
     addr.sin_port = htons(port);
     addr.sin_addr.s_addr = htonl(INADDR_ANY);
     NSData *address = [NSData dataWithBytes:&addr length:sizeof(addr)];
-    if (CFSocketSetAddress(socket, (bridge_stub CFDataRef)address) != kCFSocketSuccess) {
+    if (CFSocketSetAddress(socket, (__bridge CFDataRef)address) != kCFSocketSuccess) {
       CFSocketInvalidate(socket);
       CFRelease(socket);
-      NSLog(@"*** Could not bind to address");
+      NSLog(@"TSocketServer: Could not bind to address");
       return nil;
     }
-  } else {
-    NSLog(@"*** No server socket");
+  }
+  else {
+    NSLog(@"TSocketServer: No server socket");
     return nil;
   }
-  
+
   // wrap it in a file handle so we can get messages from it
-  mSocketFileHandle = [[NSFileHandle alloc] initWithFileDescriptor: fd
-                                                    closeOnDealloc: YES];
-  
+  _socketFileHandle = [[NSFileHandle alloc] initWithFileDescriptor:fd
+                                                    closeOnDealloc:YES];
+
   // throw away our socket
   CFSocketInvalidate(socket);
   CFRelease(socket);
-  
-    // register for notifications of accepted incoming connections
-  [[NSNotificationCenter defaultCenter] addObserver: self
-                                           selector: @selector(connectionAccepted:)
-                                               name: NSFileHandleConnectionAcceptedNotification
-                                             object: mSocketFileHandle];
-  
+
+  // register for notifications of accepted incoming connections
+  [[NSNotificationCenter defaultCenter] addObserver:self
+                                           selector:@selector(connectionAccepted:)
+                                               name:NSFileHandleConnectionAcceptedNotification
+                                             object:_socketFileHandle];
+
   // tell socket to listen
-  [mSocketFileHandle acceptConnectionInBackgroundAndNotify];
-  
-  NSLog(@"Listening on TCP port %d", port);
-  
+  [_socketFileHandle acceptConnectionInBackgroundAndNotify];
+
+  NSLog(@"TSocketServer: Listening on TCP port %d", port);
+
   return self;
 }
 
 
-- (void) dealloc {
+-(void) dealloc
+{
   [[NSNotificationCenter defaultCenter] removeObserver:self];
-  [mInputProtocolFactory release_stub];
-  [mOutputProtocolFactory release_stub];
-  [mProcessorFactory release_stub];
-  [mSocketFileHandle release_stub];
-  [super dealloc_stub];
 }
 
 
-- (void) connectionAccepted: (NSNotification *) aNotification
+-(void) connectionAccepted:(NSNotification *)notification
 {
-  NSFileHandle * socket = [[aNotification userInfo] objectForKey: NSFileHandleNotificationFileHandleItem];
+  NSFileHandle *socket = [notification.userInfo objectForKey:NSFileHandleNotificationFileHandleItem];
 
-  // now that we have a client connected, spin off a thread to handle activity
-  [NSThread detachNewThreadSelector: @selector(handleClientConnection:)
-                           toTarget: self
-                         withObject: socket];
+  // Now that we have a client connected, handle request on queue
+  dispatch_async(_processingQueue, ^{
 
-  [[aNotification object] acceptConnectionInBackgroundAndNotify];
+    [self handleClientConnection:socket];
+
+  });
+
+  // Continue accepting connections
+  [_socketFileHandle acceptConnectionInBackgroundAndNotify];
 }
 
 
-- (void) handleClientConnection: (NSFileHandle *) clientSocket
+-(void) handleClientConnection:(NSFileHandle *)clientSocket
 {
-#if __has_feature(objc_arc)
-    @autoreleasepool {
-        TNSFileHandleTransport * transport = [[TNSFileHandleTransport alloc] initWithFileHandle: clientSocket];
-        id<TProcessor> processor = [mProcessorFactory processorForTransport: transport];
-        
-        id <TProtocol> inProtocol = [mInputProtocolFactory newProtocolOnTransport: transport];
-        id <TProtocol> outProtocol = [mOutputProtocolFactory newProtocolOnTransport: transport];
-        
-        @try {
-            BOOL result = NO;
-            do {
-                @autoreleasepool {
-                    result = [processor processOnInputProtocol: inProtocol outputProtocol: outProtocol];
-                }
-            } while (result);
-        }
-        @catch (TTransportException * te) {
-            (void)te;
-            //NSLog(@"Caught transport exception, abandoning client connection: %@", te);
-        }
-        
-        NSNotification * n = [NSNotification notificationWithName: kTSocketServer_ClientConnectionFinishedForProcessorNotification
-                                                           object: self
-                                                         userInfo: [NSDictionary dictionaryWithObjectsAndKeys: 
-                                                                    processor,
-                                                                    kTSocketServer_ProcessorKey,
-                                                                    transport,
-                                                                    kTSockerServer_TransportKey,
-                                                                    nil]];
-        [[NSNotificationCenter defaultCenter] performSelectorOnMainThread: @selector(postNotification:) withObject: n waitUntilDone: YES];
-        
+  @autoreleasepool {
+
+    TNSFileHandleTransport *transport = [[TNSFileHandleTransport alloc] initWithFileHandle:clientSocket];
+    id<TProcessor> processor = [_processorFactory processorForTransport:transport];
+
+    id <TProtocol> inProtocol = [_inputProtocolFactory newProtocolOnTransport:transport];
+    id <TProtocol> outProtocol = [_outputProtocolFactory newProtocolOnTransport:transport];
+
+    NSError *error;
+    if (![processor processOnInputProtocol:inProtocol outputProtocol:outProtocol error:&error]) {
+      // Handle error
+      NSLog(@"Error processing request: %@", error);
     }
-#else
-  NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
-  
-  TNSFileHandleTransport * transport = [[TNSFileHandleTransport alloc] initWithFileHandle: clientSocket];
-  id<TProcessor> processor = [mProcessorFactory processorForTransport: transport];
-  
-  id <TProtocol> inProtocol = [[mInputProtocolFactory newProtocolOnTransport: transport] autorelease];
-  id <TProtocol> outProtocol = [[mOutputProtocolFactory newProtocolOnTransport: transport] autorelease];
 
-  @try {
-    BOOL result = NO;
-    do {
-      NSAutoreleasePool * myPool = [[NSAutoreleasePool alloc] init];
-      result = [processor processOnInputProtocol: inProtocol outputProtocol: outProtocol];
-      [myPool release];
-    } while (result);
-  }
-  @catch (TTransportException * te) {
-    //NSLog(@"Caught transport exception, abandoning client connection: %@", te);
-  }
+    dispatch_async(dispatch_get_main_queue(), ^{
 
-  NSNotification * n = [NSNotification notificationWithName: kTSocketServer_ClientConnectionFinishedForProcessorNotification
-                                                     object: self
-                                                   userInfo: [NSDictionary dictionaryWithObjectsAndKeys: 
-                                                              processor,
-                                                              kTSocketServer_ProcessorKey,
-                                                              transport,
-                                                              kTSockerServer_TransportKey,
-                                                              nil]];
-  [[NSNotificationCenter defaultCenter] performSelectorOnMainThread: @selector(postNotification:) withObject: n waitUntilDone: YES];
-  
-  [pool release];
-#endif
+      [NSNotificationCenter.defaultCenter postNotificationName:TSocketServerClientConnectionFinished
+                                                        object:self
+                                                      userInfo:@{TSocketServerProcessorKey: processor,
+                                                                 TSockerServerTransportKey: transport}];
+    });
+
+  }
 }
 
-
-
 @end
-
-
-