Thrift now a TLP - INFRA-3116
git-svn-id: https://svn.apache.org/repos/asf/thrift/branches/0.1.x@1028168 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/cocoa/README b/lib/cocoa/README
new file mode 100644
index 0000000..bbe3c93
--- /dev/null
+++ b/lib/cocoa/README
@@ -0,0 +1,21 @@
+Thrift Cocoa Software Library
+
+License
+=======
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
diff --git a/lib/cocoa/src/TApplicationException.h b/lib/cocoa/src/TApplicationException.h
new file mode 100644
index 0000000..cf1641d
--- /dev/null
+++ b/lib/cocoa/src/TApplicationException.h
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import "TException.h"
+#import "TProtocol.h"
+
+enum {
+ TApplicationException_UNKNOWN = 0,
+ TApplicationException_UNKNOWN_METHOD = 1,
+ TApplicationException_INVALID_MESSAGE_TYPE = 2,
+ TApplicationException_WRONG_METHOD_NAME = 3,
+ TApplicationException_BAD_SEQUENCE_ID = 4,
+ TApplicationException_MISSING_RESULT = 5
+};
+
+// FIXME
+@interface TApplicationException : TException {
+ int mType;
+}
+
++ (TApplicationException *) read: (id <TProtocol>) protocol;
+
+- (void) write: (id <TProtocol>) protocol;
+
++ (TApplicationException *) exceptionWithType: (int) type
+ reason: (NSString *) message;
+
+@end
diff --git a/lib/cocoa/src/TApplicationException.m b/lib/cocoa/src/TApplicationException.m
new file mode 100644
index 0000000..7068753
--- /dev/null
+++ b/lib/cocoa/src/TApplicationException.m
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import "TApplicationException.h"
+#import "TProtocolUtil.h"
+
+@implementation TApplicationException
+
+- (id) initWithType: (int) type
+ reason: (NSString *) reason
+{
+ mType = type;
+
+ NSString * name;
+ switch (type) {
+ case TApplicationException_UNKNOWN_METHOD:
+ name = @"Unknown method";
+ break;
+ case TApplicationException_INVALID_MESSAGE_TYPE:
+ name = @"Invalid message type";
+ break;
+ case TApplicationException_WRONG_METHOD_NAME:
+ name = @"Wrong method name";
+ break;
+ case TApplicationException_BAD_SEQUENCE_ID:
+ name = @"Bad sequence ID";
+ break;
+ case TApplicationException_MISSING_RESULT:
+ name = @"Missing result";
+ break;
+ default:
+ name = @"Unknown";
+ break;
+ }
+
+ self = [super initWithName: name reason: reason userInfo: nil];
+ return self;
+}
+
+
++ (TApplicationException *) read: (id <TProtocol>) protocol
+{
+ NSString * reason = nil;
+ int type = TApplicationException_UNKNOWN;
+ int fieldType;
+ int fieldID;
+
+ [protocol readStructBeginReturningName: NULL];
+
+ while (true) {
+ [protocol readFieldBeginReturningName: NULL
+ type: &fieldType
+ fieldID: &fieldID];
+ if (fieldType == TType_STOP) {
+ break;
+ }
+ switch (fieldID) {
+ case 1:
+ if (fieldType == TType_STRING) {
+ reason = [protocol readString];
+ } else {
+ [TProtocolUtil skipType: fieldType onProtocol: protocol];
+ }
+ break;
+ case 2:
+ if (fieldType == TType_I32) {
+ type = [protocol readI32];
+ } else {
+ [TProtocolUtil skipType: fieldType onProtocol: protocol];
+ }
+ break;
+ default:
+ [TProtocolUtil skipType: fieldType onProtocol: protocol];
+ break;
+ }
+ [protocol readFieldEnd];
+ }
+ [protocol readStructEnd];
+
+ return [TApplicationException exceptionWithType: type reason: reason];
+}
+
+
+- (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
+{
+ return [[[TApplicationException alloc] initWithType: type
+ reason: reason] autorelease];
+}
+
+@end
diff --git a/lib/cocoa/src/TException.h b/lib/cocoa/src/TException.h
new file mode 100644
index 0000000..b069a86
--- /dev/null
+++ b/lib/cocoa/src/TException.h
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@interface TException : NSException {
+}
+
++ (id) exceptionWithName: (NSString *) name;
+
++ (id) exceptionWithName: (NSString *) name
+ reason: (NSString *) reason;
+
++ (id) exceptionWithName: (NSString *) name
+ reason: (NSString *) reason
+ error: (NSError *) error;
+
+@end
diff --git a/lib/cocoa/src/TException.m b/lib/cocoa/src/TException.m
new file mode 100644
index 0000000..7c84199
--- /dev/null
+++ b/lib/cocoa/src/TException.m
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import "TException.h"
+
+@implementation TException
+
++ (id) exceptionWithName: (NSString *) name
+{
+ return [self exceptionWithName: name reason: @"unknown" error: nil];
+}
+
+
++ (id) exceptionWithName: (NSString *) name
+ reason: (NSString *) reason
+{
+ return [self exceptionWithName: name reason: reason error: nil];
+}
+
+
++ (id) exceptionWithName: (NSString *) name
+ reason: (NSString *) reason
+ error: (NSError *) error
+{
+ NSDictionary * userInfo = nil;
+ if (error != nil) {
+ userInfo = [NSDictionary dictionaryWithObject: error forKey: @"error"];
+ }
+
+ return [super exceptionWithName: name
+ reason: reason
+ userInfo: userInfo];
+}
+
+
+- (NSString *) description
+{
+ NSMutableString * result = [NSMutableString stringWithString: [self name]];
+ [result appendFormat: @": %@", [self reason]];
+ if ([self userInfo] != nil) {
+ [result appendFormat: @"\n userInfo = %@", [self userInfo]];
+ }
+
+ return result;
+}
+
+
+@end
diff --git a/lib/cocoa/src/TProcessor.h b/lib/cocoa/src/TProcessor.h
new file mode 100644
index 0000000..f8df225
--- /dev/null
+++ b/lib/cocoa/src/TProcessor.h
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+
+@protocol TProcessor <NSObject>
+
+- (BOOL) processOnInputProtocol: (id <TProtocol>) inProtocol
+ outputProtocol: (id <TProtocol>) outProtocol;
+
+@end
diff --git a/lib/cocoa/src/protocol/TBinaryProtocol.h b/lib/cocoa/src/protocol/TBinaryProtocol.h
new file mode 100644
index 0000000..52cf266
--- /dev/null
+++ b/lib/cocoa/src/protocol/TBinaryProtocol.h
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import "TProtocol.h"
+#import "TTransport.h"
+#import "TProtocolFactory.h"
+
+
+@interface TBinaryProtocol : NSObject <TProtocol> {
+ id <TTransport> mTransport;
+ BOOL mStrictRead;
+ BOOL mStrictWrite;
+ int32_t mMessageSizeLimit;
+}
+
+- (id) initWithTransport: (id <TTransport>) transport;
+
+- (id) initWithTransport: (id <TTransport>) transport
+ strictRead: (BOOL) strictRead
+ strictWrite: (BOOL) strictWrite;
+
+- (int32_t) messageSizeLimit;
+- (void) setMessageSizeLimit: (int32_t) sizeLimit;
+
+@end;
+
+
+@interface TBinaryProtocolFactory : NSObject <TProtocolFactory> {
+}
+
++ (TBinaryProtocolFactory *) sharedFactory;
+
+- (TBinaryProtocol *) newProtocolOnTransport: (id <TTransport>) transport;
+
+@end
diff --git a/lib/cocoa/src/protocol/TBinaryProtocol.m b/lib/cocoa/src/protocol/TBinaryProtocol.m
new file mode 100644
index 0000000..ba7f462
--- /dev/null
+++ b/lib/cocoa/src/protocol/TBinaryProtocol.m
@@ -0,0 +1,469 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import "TBinaryProtocol.h"
+#import "TProtocolException.h"
+
+int32_t VERSION_1 = 0x80010000;
+int32_t VERSION_MASK = 0xffff0000;
+
+
+static TBinaryProtocolFactory * gSharedFactory = nil;
+
+@implementation TBinaryProtocolFactory
+
++ (TBinaryProtocolFactory *) sharedFactory {
+ if (gSharedFactory == nil) {
+ gSharedFactory = [[TBinaryProtocolFactory alloc] init];
+ }
+
+ return gSharedFactory;
+}
+
+- (TBinaryProtocol *) newProtocolOnTransport: (id <TTransport>) transport {
+ return [[[TBinaryProtocol alloc] initWithTransport: transport] autorelease];
+}
+
+@end
+
+
+
+@implementation TBinaryProtocol
+
+- (id) initWithTransport: (id <TTransport>) transport
+{
+ return [self initWithTransport: transport strictRead: NO strictWrite: NO];
+}
+
+- (id) initWithTransport: (id <TTransport>) transport
+ strictRead: (BOOL) strictRead
+ strictWrite: (BOOL) strictWrite
+{
+ self = [super init];
+ mTransport = [transport retain];
+ mStrictRead = strictRead;
+ mStrictWrite = strictWrite;
+ return self;
+}
+
+
+- (int32_t) messageSizeLimit
+{
+ return mMessageSizeLimit;
+}
+
+
+- (void) setMessageSizeLimit: (int32_t) sizeLimit
+{
+ mMessageSizeLimit = sizeLimit;
+}
+
+
+- (void) dealloc
+{
+ [mTransport release];
+ [super dealloc];
+}
+
+
+- (id <TTransport>) transport
+{
+ return mTransport;
+}
+
+
+- (NSString *) readStringBody: (int) size
+{
+ char buff[size+1];
+ [mTransport readAll: (uint8_t *) buff offset: 0 length: size];
+ buff[size] = 0;
+ return [NSString stringWithUTF8String: buff];
+}
+
+
+- (void) readMessageBeginReturningName: (NSString **) name
+ type: (int *) type
+ sequenceID: (int *) sequenceID
+{
+ int32_t size = [self readI32];
+ if (size < 0) {
+ int version = size & VERSION_MASK;
+ if (version != VERSION_1) {
+ @throw [TProtocolException exceptionWithName: @"TProtocolException"
+ reason: @"Bad version in readMessageBegin"];
+ }
+ if (type != NULL) {
+ *type = version & 0x00FF;
+ }
+ NSString * messageName = [self readString];
+ if (name != NULL) {
+ *name = messageName;
+ }
+ int seqID = [self readI32];
+ if (sequenceID != NULL) {
+ *sequenceID = seqID;
+ }
+ } else {
+ if (mStrictRead) {
+ @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;
+ }
+ int messageType = [self readByte];
+ if (type != NULL) {
+ *type = messageType;
+ }
+ int seqID = [self readI32];
+ if (sequenceID != NULL) {
+ *sequenceID = seqID;
+ }
+ }
+}
+
+
+- (void) readMessageEnd {}
+
+
+- (void) readStructBeginReturningName: (NSString **) name
+{
+ if (name != NULL) {
+ *name = nil;
+ }
+}
+
+
+- (void) readStructEnd {}
+
+
+- (void) readFieldBeginReturningName: (NSString **) name
+ type: (int *) fieldType
+ fieldID: (int *) fieldID
+{
+ if (name != NULL) {
+ *name = nil;
+ }
+ int ft = [self readByte];
+ if (fieldType != NULL) {
+ *fieldType = ft;
+ }
+ if (ft != TType_STOP) {
+ int fid = [self readI16];
+ if (fieldID != NULL) {
+ *fieldID = fid;
+ }
+ }
+}
+
+
+- (void) readFieldEnd {}
+
+
+- (int32_t) readI32
+{
+ uint8_t i32rd[4];
+ [mTransport readAll: i32rd offset: 0 length: 4];
+ return
+ ((i32rd[0] & 0xff) << 24) |
+ ((i32rd[1] & 0xff) << 16) |
+ ((i32rd[2] & 0xff) << 8) |
+ ((i32rd[3] & 0xff));
+}
+
+
+- (NSString *) readString
+{
+ int size = [self readI32];
+ return [self readStringBody: size];
+}
+
+
+- (BOOL) readBool
+{
+ return [self readByte] == 1;
+}
+
+- (uint8_t) readByte
+{
+ uint8_t myByte;
+ [mTransport readAll: &myByte offset: 0 length: 1];
+ return myByte;
+}
+
+- (short) readI16
+{
+ uint8_t buff[2];
+ [mTransport readAll: buff offset: 0 length: 2];
+ return (short)
+ (((buff[0] & 0xff) << 8) |
+ ((buff[1] & 0xff)));
+ return 0;
+}
+
+- (int64_t) readI64;
+{
+ uint8_t i64rd[8];
+ [mTransport readAll: i64rd offset: 0 length: 8];
+ return
+ ((int64_t)(i64rd[0] & 0xff) << 56) |
+ ((int64_t)(i64rd[1] & 0xff) << 48) |
+ ((int64_t)(i64rd[2] & 0xff) << 40) |
+ ((int64_t)(i64rd[3] & 0xff) << 32) |
+ ((int64_t)(i64rd[4] & 0xff) << 24) |
+ ((int64_t)(i64rd[5] & 0xff) << 16) |
+ ((int64_t)(i64rd[6] & 0xff) << 8) |
+ ((int64_t)(i64rd[7] & 0xff));
+}
+
+- (double) readDouble;
+{
+ // FIXME - will this get us into trouble on PowerPC?
+ int64_t ieee754 = [self readI64];
+ return *((double *) &ieee754);
+}
+
+
+- (NSData *) readBinary
+{
+ int32_t size = [self readI32];
+ uint8_t * buff = malloc(size);
+ if (buff == NULL) {
+ @throw [TProtocolException
+ exceptionWithName: @"TProtocolException"
+ reason: [NSString stringWithFormat: @"Out of memory. Unable to allocate %d bytes trying to read binary data.",
+ size]];
+ }
+ [mTransport readAll: buff offset: 0 length: size];
+ return [NSData dataWithBytesNoCopy: buff length: size];
+}
+
+
+- (void) readMapBeginReturningKeyType: (int *) keyType
+ valueType: (int *) valueType
+ size: (int *) size
+{
+ int kt = [self readByte];
+ int vt = [self readByte];
+ int s = [self readI32];
+ if (keyType != NULL) {
+ *keyType = kt;
+ }
+ if (valueType != NULL) {
+ *valueType = vt;
+ }
+ if (size != NULL) {
+ *size = s;
+ }
+}
+
+- (void) readMapEnd {}
+
+
+- (void) readSetBeginReturningElementType: (int *) elementType
+ size: (int *) size
+{
+ int et = [self readByte];
+ int s = [self readI32];
+ if (elementType != NULL) {
+ *elementType = et;
+ }
+ if (size != NULL) {
+ *size = s;
+ }
+}
+
+
+- (void) readSetEnd {}
+
+
+- (void) readListBeginReturningElementType: (int *) elementType
+ size: (int *) size
+{
+ int et = [self readByte];
+ int s = [self readI32];
+ if (elementType != NULL) {
+ *elementType = et;
+ }
+ if (size != NULL) {
+ *size = s;
+ }
+}
+
+
+- (void) readListEnd {}
+
+
+- (void) writeByte: (uint8_t) value
+{
+ [mTransport write: &value offset: 0 length: 1];
+}
+
+
+- (void) writeMessageBeginWithName: (NSString *) name
+ type: (int) messageType
+ sequenceID: (int) sequenceID
+{
+ if (mStrictWrite) {
+ int version = VERSION_1 | messageType;
+ [self writeI32: version];
+ [self writeString: name];
+ [self writeI32: sequenceID];
+ } else {
+ [self writeString: name];
+ [self writeByte: messageType];
+ [self writeI32: sequenceID];
+ }
+}
+
+
+- (void) writeMessageEnd {}
+
+
+- (void) writeStructBeginWithName: (NSString *) name {}
+
+
+- (void) writeStructEnd {}
+
+
+- (void) writeFieldBeginWithName: (NSString *) name
+ type: (int) fieldType
+ fieldID: (int) fieldID
+{
+ [self writeByte: fieldType];
+ [self writeI16: fieldID];
+}
+
+
+- (void) writeI32: (int32_t) value
+{
+ uint8_t buff[4];
+ buff[0] = 0xFF & (value >> 24);
+ buff[1] = 0xFF & (value >> 16);
+ buff[2] = 0xFF & (value >> 8);
+ buff[3] = 0xFF & value;
+ [mTransport write: buff offset: 0 length: 4];
+}
+
+- (void) writeI16: (short) value
+{
+ uint8_t buff[2];
+ buff[0] = 0xff & (value >> 8);
+ buff[1] = 0xff & value;
+ [mTransport write: buff offset: 0 length: 2];
+}
+
+
+- (void) writeI64: (int64_t) value
+{
+ uint8_t buff[8];
+ buff[0] = 0xFF & (value >> 56);
+ buff[1] = 0xFF & (value >> 48);
+ buff[2] = 0xFF & (value >> 40);
+ buff[3] = 0xFF & (value >> 32);
+ buff[4] = 0xFF & (value >> 24);
+ buff[5] = 0xFF & (value >> 16);
+ buff[6] = 0xFF & (value >> 8);
+ buff[7] = 0xFF & value;
+ [mTransport write: buff offset: 0 length: 8];
+}
+
+- (void) writeDouble: (double) value
+{
+ // spit out IEEE 754 bits - FIXME - will this get us in trouble on
+ // PowerPC?
+ [self writeI64: *((int64_t *) &value)];
+}
+
+
+- (void) writeString: (NSString *) value
+{
+ if (value != nil) {
+ const char * utf8Bytes = [value UTF8String];
+ size_t length = strlen(utf8Bytes);
+ [self writeI32: length];
+ [mTransport write: (uint8_t *) utf8Bytes offset: 0 length: length];
+ } else {
+ // instead of crashing when we get null, let's write out a zero
+ // length string
+ [self writeI32: 0];
+ }
+}
+
+
+- (void) writeBinary: (NSData *) data
+{
+ [self writeI32: [data length]];
+ [mTransport write: [data bytes] offset: 0 length: [data length]];
+}
+
+- (void) writeFieldStop
+{
+ [self writeByte: TType_STOP];
+}
+
+
+- (void) writeFieldEnd {}
+
+
+- (void) writeMapBeginWithKeyType: (int) keyType
+ valueType: (int) valueType
+ size: (int) size
+{
+ [self writeByte: keyType];
+ [self writeByte: valueType];
+ [self writeI32: size];
+}
+
+- (void) writeMapEnd {}
+
+
+- (void) writeSetBeginWithElementType: (int) elementType
+ size: (int) size
+{
+ [self writeByte: elementType];
+ [self writeI32: size];
+}
+
+- (void) writeSetEnd {}
+
+
+- (void) writeListBeginWithElementType: (int) elementType
+ size: (int) size
+{
+ [self writeByte: elementType];
+ [self writeI32: size];
+}
+
+- (void) writeListEnd {}
+
+
+- (void) writeBool: (BOOL) value
+{
+ [self writeByte: (value ? 1 : 0)];
+}
+
+@end
diff --git a/lib/cocoa/src/protocol/TProtocol.h b/lib/cocoa/src/protocol/TProtocol.h
new file mode 100644
index 0000000..cc8cdb4
--- /dev/null
+++ b/lib/cocoa/src/protocol/TProtocol.h
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+#import "TTransport.h"
+
+
+enum {
+ TMessageType_CALL = 1,
+ TMessageType_REPLY = 2,
+ TMessageType_EXCEPTION = 3,
+ TMessageType_ONEWAY = 4
+};
+
+enum {
+ TType_STOP = 0,
+ TType_VOID = 1,
+ TType_BOOL = 2,
+ TType_BYTE = 3,
+ TType_DOUBLE = 4,
+ TType_I16 = 6,
+ TType_I32 = 8,
+ TType_I64 = 10,
+ TType_STRING = 11,
+ TType_STRUCT = 12,
+ TType_MAP = 13,
+ TType_SET = 14,
+ TType_LIST = 15
+};
+
+
+@protocol TProtocol <NSObject>
+
+- (id <TTransport>) transport;
+
+- (void) readMessageBeginReturningName: (NSString **) name
+ type: (int *) type
+ sequenceID: (int *) sequenceID;
+- (void) readMessageEnd;
+
+- (void) readStructBeginReturningName: (NSString **) name;
+- (void) readStructEnd;
+
+- (void) readFieldBeginReturningName: (NSString **) name
+ type: (int *) fieldType
+ fieldID: (int *) fieldID;
+- (void) readFieldEnd;
+
+- (NSString *) readString;
+
+- (BOOL) readBool;
+
+- (unsigned char) readByte;
+
+- (short) readI16;
+
+- (int32_t) readI32;
+
+- (int64_t) readI64;
+
+- (double) readDouble;
+
+- (NSData *) readBinary;
+
+- (void) readMapBeginReturningKeyType: (int *) keyType
+ valueType: (int *) valueType
+ size: (int *) size;
+- (void) readMapEnd;
+
+
+- (void) readSetBeginReturningElementType: (int *) elementType
+ size: (int *) size;
+- (void) readSetEnd;
+
+
+- (void) readListBeginReturningElementType: (int *) elementType
+ size: (int *) size;
+- (void) readListEnd;
+
+
+- (void) writeMessageBeginWithName: (NSString *) name
+ type: (int) messageType
+ sequenceID: (int) sequenceID;
+- (void) writeMessageEnd;
+
+- (void) writeStructBeginWithName: (NSString *) name;
+- (void) writeStructEnd;
+
+- (void) writeFieldBeginWithName: (NSString *) name
+ type: (int) fieldType
+ fieldID: (int) fieldID;
+
+- (void) writeI32: (int32_t) value;
+
+- (void) writeI64: (int64_t) value;
+
+- (void) writeI16: (short) value;
+
+- (void) writeByte: (uint8_t) value;
+
+- (void) writeString: (NSString *) value;
+
+- (void) writeDouble: (double) value;
+
+- (void) writeBool: (BOOL) value;
+
+- (void) writeBinary: (NSData *) data;
+
+- (void) writeFieldStop;
+
+- (void) writeFieldEnd;
+
+- (void) writeMapBeginWithKeyType: (int) keyType
+ valueType: (int) valueType
+ size: (int) size;
+- (void) writeMapEnd;
+
+
+- (void) writeSetBeginWithElementType: (int) elementType
+ size: (int) size;
+- (void) writeSetEnd;
+
+
+- (void) writeListBeginWithElementType: (int) elementType
+ size: (int) size;
+
+- (void) writeListEnd;
+
+
+@end
+
diff --git a/lib/cocoa/src/protocol/TProtocolException.h b/lib/cocoa/src/protocol/TProtocolException.h
new file mode 100644
index 0000000..ad354fc
--- /dev/null
+++ b/lib/cocoa/src/protocol/TProtocolException.h
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import "TException.h"
+
+@interface TProtocolException : TException {
+}
+
+@end
diff --git a/lib/cocoa/src/protocol/TProtocolException.m b/lib/cocoa/src/protocol/TProtocolException.m
new file mode 100644
index 0000000..681487a
--- /dev/null
+++ b/lib/cocoa/src/protocol/TProtocolException.m
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import "TProtocolException.h"
+
+@implementation TProtocolException
+@end
diff --git a/lib/cocoa/src/protocol/TProtocolFactory.h b/lib/cocoa/src/protocol/TProtocolFactory.h
new file mode 100644
index 0000000..2d125e9
--- /dev/null
+++ b/lib/cocoa/src/protocol/TProtocolFactory.h
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import <Cocoa/Cocoa.h>
+#import "TProtocol.h"
+#import "TTransport.h"
+
+
+@protocol TProtocolFactory <NSObject>
+
+- (id <TProtocol>) newProtocolOnTransport: (id <TTransport>) transport;
+
+@end
diff --git a/lib/cocoa/src/protocol/TProtocolUtil.h b/lib/cocoa/src/protocol/TProtocolUtil.h
new file mode 100644
index 0000000..c2d2521
--- /dev/null
+++ b/lib/cocoa/src/protocol/TProtocolUtil.h
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import "TProtocol.h"
+#import "TTransport.h"
+
+@interface TProtocolUtil : NSObject {
+
+}
+
++ (void) skipType: (int) type onProtocol: (id <TProtocol>) protocol;
+
+@end;
diff --git a/lib/cocoa/src/protocol/TProtocolUtil.m b/lib/cocoa/src/protocol/TProtocolUtil.m
new file mode 100644
index 0000000..13d7095
--- /dev/null
+++ b/lib/cocoa/src/protocol/TProtocolUtil.m
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import "TProtocolUtil.h"
+
+@implementation TProtocolUtil
+
++ (void) skipType: (int) type onProtocol: (id <TProtocol>) protocol
+{
+ switch (type) {
+ case TType_BOOL:
+ [protocol readBool];
+ break;
+ case TType_BYTE:
+ [protocol readByte];
+ break;
+ case TType_I16:
+ [protocol readI16];
+ break;
+ case TType_I32:
+ [protocol readI32];
+ break;
+ case TType_I64:
+ [protocol readI64];
+ break;
+ case TType_DOUBLE:
+ [protocol readDouble];
+ break;
+ case TType_STRING:
+ [protocol readString];
+ break;
+ case TType_STRUCT:
+ [protocol readStructBeginReturningName: NULL];
+ while (true) {
+ int fieldType;
+ [protocol readFieldBeginReturningName: nil type: &fieldType fieldID: nil];
+ if (fieldType == TType_STOP) {
+ break;
+ }
+ [TProtocolUtil skipType: fieldType onProtocol: protocol];
+ [protocol readFieldEnd];
+ }
+ [protocol readStructEnd];
+ break;
+ case TType_MAP:
+ {
+ int keyType;
+ int valueType;
+ int size;
+ [protocol readMapBeginReturningKeyType: &keyType valueType: &valueType size: &size];
+ int i;
+ for (i = 0; i < size; i++) {
+ [TProtocolUtil skipType: keyType onProtocol: protocol];
+ [TProtocolUtil skipType: valueType onProtocol: protocol];
+ }
+ [protocol readMapEnd];
+ }
+ break;
+ case TType_SET:
+ {
+ int elemType;
+ int size;
+ [protocol readSetBeginReturningElementType: &elemType size: &size];
+ int i;
+ for (i = 0; i < size; i++) {
+ [TProtocolUtil skipType: elemType onProtocol: protocol];
+ }
+ [protocol readSetEnd];
+ }
+ break;
+ case TType_LIST:
+ {
+ int elemType;
+ int size;
+ [protocol readListBeginReturningElementType: &elemType size: &size];
+ int i;
+ for (i = 0; i < size; i++) {
+ [TProtocolUtil skipType: elemType onProtocol: protocol];
+ }
+ [protocol readListEnd];
+ }
+ break;
+ default:
+ return;
+ }
+}
+
+@end
diff --git a/lib/cocoa/src/server/TSocketServer.h b/lib/cocoa/src/server/TSocketServer.h
new file mode 100644
index 0000000..3d4a9e0
--- /dev/null
+++ b/lib/cocoa/src/server/TSocketServer.h
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import <Cocoa/Cocoa.h>
+#import "TProtocolFactory.h"
+#import "TProcessor.h"
+
+
+@interface TSocketServer : NSObject {
+ NSSocketPort * mServerSocket;
+ NSFileHandle * mSocketFileHandle;
+ id <TProtocolFactory> mInputProtocolFactory;
+ id <TProtocolFactory> mOutputProtocolFactory;
+ id <TProcessor> mProcessor;
+}
+
+- (id) initWithPort: (int) port
+ protocolFactory: (id <TProtocolFactory>) protocolFactory
+ processor: (id <TProcessor>) processor;
+
+@end
+
+
+
diff --git a/lib/cocoa/src/server/TSocketServer.m b/lib/cocoa/src/server/TSocketServer.m
new file mode 100644
index 0000000..97d8bae
--- /dev/null
+++ b/lib/cocoa/src/server/TSocketServer.m
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import <Cocoa/Cocoa.h>
+#import "TSocketServer.h"
+#import "TNSFileHandleTransport.h"
+#import "TProtocol.h"
+#import "TTransportException.h"
+
+
+@implementation TSocketServer
+
+- (id) initWithPort: (int) port
+ protocolFactory: (id <TProtocolFactory>) protocolFactory
+ processor: (id <TProcessor>) processor;
+{
+ self = [super init];
+
+ mInputProtocolFactory = [protocolFactory retain];
+ mOutputProtocolFactory = [protocolFactory retain];
+ mProcessor = [processor retain];
+
+ // create a socket
+ 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);
+
+ // 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;
+}
+
+
+- (void) dealloc {
+ [mInputProtocolFactory release];
+ [mOutputProtocolFactory release];
+ [mProcessor release];
+ [mSocketFileHandle release];
+ [mServerSocket release];
+ [super dealloc];
+}
+
+
+- (void) connectionAccepted: (NSNotification *) aNotification
+{
+ NSFileHandle * socket = [[aNotification 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];
+
+ [[aNotification object] acceptConnectionInBackgroundAndNotify];
+}
+
+
+- (void) handleClientConnection: (NSFileHandle *) clientSocket
+{
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+
+ TNSFileHandleTransport * transport = [[TNSFileHandleTransport alloc] initWithFileHandle: clientSocket];
+
+ id <TProtocol> inProtocol = [mInputProtocolFactory newProtocolOnTransport: transport];
+ id <TProtocol> outProtocol = [mOutputProtocolFactory newProtocolOnTransport: transport];
+
+ @try {
+ while ([mProcessor processOnInputProtocol: inProtocol outputProtocol: outProtocol]);
+ }
+ @catch (TTransportException * te) {
+ NSLog(@"%@", te);
+ }
+
+ [pool release];
+}
+
+
+
+@end
+
+
+
diff --git a/lib/cocoa/src/transport/THTTPClient.h b/lib/cocoa/src/transport/THTTPClient.h
new file mode 100644
index 0000000..86f3f05
--- /dev/null
+++ b/lib/cocoa/src/transport/THTTPClient.h
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import <Cocoa/Cocoa.h>
+#import "TTransport.h"
+
+@interface THTTPClient : NSObject <TTransport> {
+ NSURL * mURL;
+ NSMutableURLRequest * mRequest;
+ NSMutableData * mRequestData;
+ NSData * mResponseData;
+ int mResponseDataOffset;
+ NSString * mUserAgent;
+ int mTimeout;
+}
+
+- (id) initWithURL: (NSURL *) aURL;
+
+- (id) initWithURL: (NSURL *) aURL
+ userAgent: (NSString *) userAgent
+ timeout: (int) timeout;
+
+- (void) setURL: (NSURL *) aURL;
+
+@end
+
diff --git a/lib/cocoa/src/transport/THTTPClient.m b/lib/cocoa/src/transport/THTTPClient.m
new file mode 100644
index 0000000..6391bea
--- /dev/null
+++ b/lib/cocoa/src/transport/THTTPClient.m
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import "THTTPClient.h"
+#import "TTransportException.h"
+
+@implementation THTTPClient
+
+
+- (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"];
+ [mRequest setValue: @"application/x-thrift" forHTTPHeaderField: @"Content-Type"];
+ [mRequest setValue: @"application/x-thrift" forHTTPHeaderField: @"Accept"];
+
+ NSString * userAgent = mUserAgent;
+ if (!userAgent) {
+ userAgent = @"Cocoa/THTTPClient";
+ }
+ [mRequest setValue: userAgent forHTTPHeaderField: @"User-Agent"];
+
+ [mRequest setCachePolicy: NSURLRequestReloadIgnoringCacheData];
+ if (mTimeout) {
+ [mRequest setTimeoutInterval: mTimeout];
+ }
+}
+
+
+- (id) initWithURL: (NSURL *) aURL
+{
+ return [self initWithURL: aURL
+ userAgent: nil
+ timeout: 0];
+}
+
+
+- (id) initWithURL: (NSURL *) aURL
+ userAgent: (NSString *) userAgent
+ timeout: (int) timeout
+{
+ self = [super init];
+ if (!self) {
+ return nil;
+ }
+
+ mTimeout = timeout;
+ if (userAgent) {
+ mUserAgent = [userAgent retain];
+ }
+ mURL = [aURL retain];
+
+ [self setupRequest];
+
+ // create our request data buffer
+ mRequestData = [[NSMutableData alloc] initWithCapacity: 1024];
+
+ return self;
+}
+
+
+- (void) setURL: (NSURL *) aURL
+{
+ [aURL retain];
+ [mURL release];
+ mURL = aURL;
+
+ [self setupRequest];
+}
+
+
+- (void) dealloc
+{
+ [mURL release];
+ [mUserAgent release];
+ [mRequest release];
+ [mRequestData release];
+ [mResponseData release];
+ [super dealloc];
+}
+
+
+- (int) readAll: (uint8_t *) buf offset: (int) off length: (int) len
+{
+ NSRange r;
+ r.location = mResponseDataOffset;
+ r.length = len;
+
+ [mResponseData getBytes: buf+off range: r];
+ mResponseDataOffset += len;
+
+ return len;
+}
+
+
+- (void) write: (const uint8_t *) data offset: (unsigned int) offset length: (unsigned int) length
+{
+ [mRequestData appendBytes: data+offset length: length];
+}
+
+
+- (void) flush
+{
+ [mRequest setHTTPBody: mRequestData]; // not sure if it copies the data
+
+ // make the HTTP request
+ NSURLResponse * response;
+ NSError * error;
+ NSData * responseData =
+ [NSURLConnection sendSynchronousRequest: mRequest returningResponse: &response error: &error];
+
+ [mRequestData setLength: 0];
+
+ if (responseData == nil) {
+ @throw [TTransportException exceptionWithName: @"TTransportException"
+ reason: @"Could not make HTTP request"
+ error: error];
+ }
+ if (![response isKindOfClass: [NSHTTPURLResponse class]]) {
+ @throw [TTransportException exceptionWithName: @"TTransportException"
+ reason: @"Unexpected NSURLResponse type"];
+ }
+
+ NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *) response;
+ if ([httpResponse statusCode] != 200) {
+ @throw [TTransportException exceptionWithName: @"TTransportException"
+ reason: [NSString stringWithFormat: @"Bad response from HTTP server: %d",
+ [httpResponse statusCode]]];
+ }
+
+ // phew!
+ [mResponseData release];
+ mResponseData = [responseData retain];
+ mResponseDataOffset = 0;
+}
+
+
+@end
diff --git a/lib/cocoa/src/transport/TNSFileHandleTransport.h b/lib/cocoa/src/transport/TNSFileHandleTransport.h
new file mode 100644
index 0000000..64a6af3
--- /dev/null
+++ b/lib/cocoa/src/transport/TNSFileHandleTransport.h
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+#import <Cocoa/Cocoa.h>
+#import "TTransport.h"
+
+@interface TNSFileHandleTransport : NSObject <TTransport> {
+ NSFileHandle * mInputFileHandle;
+ NSFileHandle * mOutputFileHandle;
+}
+
+- (id) initWithFileHandle: (NSFileHandle *) fileHandle;
+
+- (id) initWithInputFileHandle: (NSFileHandle *) inputFileHandle
+ outputFileHandle: (NSFileHandle *) outputFileHandle;
+
+
+@end
diff --git a/lib/cocoa/src/transport/TNSFileHandleTransport.m b/lib/cocoa/src/transport/TNSFileHandleTransport.m
new file mode 100644
index 0000000..1533934
--- /dev/null
+++ b/lib/cocoa/src/transport/TNSFileHandleTransport.m
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+#import "TNSFileHandleTransport.h"
+#import "TTransportException.h"
+
+
+@implementation TNSFileHandleTransport
+
+- (id) initWithFileHandle: (NSFileHandle *) fileHandle
+{
+ return [self initWithInputFileHandle: fileHandle
+ outputFileHandle: fileHandle];
+}
+
+
+- (id) initWithInputFileHandle: (NSFileHandle *) inputFileHandle
+ outputFileHandle: (NSFileHandle *) outputFileHandle
+{
+ self = [super init];
+
+ mInputFileHandle = [inputFileHandle retain];
+ mOutputFileHandle = [outputFileHandle retain];
+
+ return self;
+}
+
+
+- (void) dealloc {
+ [mInputFileHandle release];
+ [mOutputFileHandle release];
+ [super dealloc];
+}
+
+
+- (int) readAll: (uint8_t *) buf offset: (int) off length: (int) len
+{
+ int got = 0;
+ while (got < len) {
+ NSData * d = [mInputFileHandle readDataOfLength: len-got];
+ if ([d length] == 0) {
+ @throw [TTransportException exceptionWithName: @"TTransportException"
+ reason: @"Cannot read. No more data."];
+ }
+ [d getBytes: buf+got];
+ got += [d length];
+ }
+ return got;
+}
+
+
+- (void) write: (uint8_t *) data offset: (unsigned int) offset length: (unsigned int) length
+{
+ NSData * dataObject = [[NSData alloc] initWithBytesNoCopy: data+offset
+ length: length
+ freeWhenDone: NO];
+
+ [mOutputFileHandle writeData: dataObject];
+
+
+ [dataObject release];
+}
+
+
+- (void) flush
+{
+
+}
+
+@end
diff --git a/lib/cocoa/src/transport/TNSStreamTransport.h b/lib/cocoa/src/transport/TNSStreamTransport.h
new file mode 100644
index 0000000..295a185
--- /dev/null
+++ b/lib/cocoa/src/transport/TNSStreamTransport.h
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import <Cocoa/Cocoa.h>
+#import "TTransport.h"
+
+@interface TNSStreamTransport : NSObject <TTransport> {
+ NSInputStream * mInput;
+ NSOutputStream * mOutput;
+}
+
+- (id) initWithInputStream: (NSInputStream *) input
+ outputStream: (NSOutputStream *) output;
+
+- (id) initWithInputStream: (NSInputStream *) input;
+
+- (id) initWithOutputStream: (NSOutputStream *) output;
+
+@end
+
+
+
diff --git a/lib/cocoa/src/transport/TNSStreamTransport.m b/lib/cocoa/src/transport/TNSStreamTransport.m
new file mode 100644
index 0000000..52a02e2
--- /dev/null
+++ b/lib/cocoa/src/transport/TNSStreamTransport.m
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import "TNSStreamTransport.h"
+#import "TTransportException.h"
+
+
+@implementation TNSStreamTransport
+
+- (id) initWithInputStream: (NSInputStream *) input
+ outputStream: (NSOutputStream *) output
+{
+ [super init];
+ mInput = [input retain];
+ mOutput = [output retain];
+ return self;
+}
+
+- (id) initWithInputStream: (NSInputStream *) input
+{
+ return [self initWithInputStream: input outputStream: nil];
+}
+
+- (id) initWithOutputStream: (NSOutputStream *) output
+{
+ return [self initWithInputStream: nil outputStream: output];
+}
+
+- (void) dealloc
+{
+ [mInput release];
+ [mOutput release];
+ [super dealloc];
+}
+
+
+- (int) readAll: (uint8_t *) buf offset: (int) off length: (int) len
+{
+ int got = 0;
+ int ret = 0;
+ while (got < len) {
+ ret = [mInput read: buf+off+got maxLength: len-got];
+ if (ret <= 0) {
+ @throw [TTransportException exceptionWithReason: @"Cannot read. Remote side has closed."];
+ }
+ got += ret;
+ }
+ return got;
+}
+
+
+// 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) {
+ @throw [TTransportException exceptionWithReason: @"Error writing to transport output stream."
+ error: [mOutput streamError]];
+ } else if (result == 0) {
+ @throw [TTransportException exceptionWithReason: @"End of output stream."];
+ } else if (result != length) {
+ @throw [TTransportException exceptionWithReason: @"Output stream did not write all of our data."];
+ }
+}
+
+- (void) flush
+{
+ // no flush for you!
+}
+
+@end
diff --git a/lib/cocoa/src/transport/TSocketClient.h b/lib/cocoa/src/transport/TSocketClient.h
new file mode 100644
index 0000000..a883acb
--- /dev/null
+++ b/lib/cocoa/src/transport/TSocketClient.h
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import <Cocoa/Cocoa.h>
+#import "TNSStreamTransport.h"
+
+@interface TSocketClient : TNSStreamTransport {
+}
+
+- (id) initWithHostname: (NSString *) hostname
+ port: (int) port;
+
+@end
+
+
+
diff --git a/lib/cocoa/src/transport/TSocketClient.m b/lib/cocoa/src/transport/TSocketClient.m
new file mode 100644
index 0000000..7c07c56
--- /dev/null
+++ b/lib/cocoa/src/transport/TSocketClient.m
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import <Cocoa/Cocoa.h>
+#import "TSocketClient.h"
+
+@implementation TSocketClient
+
+- (id) initWithHostname: (NSString *) hostname
+ port: (int) port
+{
+ NSInputStream * input = nil;
+ NSOutputStream * output = nil;
+
+ [NSStream getStreamsToHost: [NSHost hostWithName: hostname]
+ port: port
+ inputStream: &input
+ outputStream: &output];
+
+ self = [super initWithInputStream: input outputStream: output];
+ [input open];
+ [output open];
+
+ return self;
+}
+
+
+@end
+
+
+
diff --git a/lib/cocoa/src/transport/TTransport.h b/lib/cocoa/src/transport/TTransport.h
new file mode 100644
index 0000000..61ebbd2
--- /dev/null
+++ b/lib/cocoa/src/transport/TTransport.h
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+@protocol TTransport <NSObject>
+
+ /**
+ * Guarantees that all of len bytes are read
+ *
+ * @param buf Buffer to read into
+ * @param off Index in buffer to start storing bytes at
+ * @param len Maximum number of bytes to read
+ * @return The number of bytes actually read, which must be equal to len
+ * @throws TTransportException if there was an error reading data
+ */
+- (int) readAll: (uint8_t *) buf offset: (int) off length: (int) len;
+
+- (void) write: (const uint8_t *) data offset: (unsigned int) offset length: (unsigned int) length;
+
+- (void) flush;
+@end
diff --git a/lib/cocoa/src/transport/TTransportException.h b/lib/cocoa/src/transport/TTransportException.h
new file mode 100644
index 0000000..6749fe2
--- /dev/null
+++ b/lib/cocoa/src/transport/TTransportException.h
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import "TException.h"
+
+@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
new file mode 100644
index 0000000..aa67149
--- /dev/null
+++ b/lib/cocoa/src/transport/TTransportException.m
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#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