THRIFT-3041 Generate asynchronous clients for Cocoa
Client: Cocoa
Patch: Mike Riley <mikeriley@yelirekim.com>
This closes #400
diff --git a/compiler/cpp/src/generate/t_cocoa_generator.cc b/compiler/cpp/src/generate/t_cocoa_generator.cc
index 3cb9127..a87ef4a 100644
--- a/compiler/cpp/src/generate/t_cocoa_generator.cc
+++ b/compiler/cpp/src/generate/t_cocoa_generator.cc
@@ -57,6 +57,9 @@
iter = parsed_options.find("validate_required");
validate_required_ = (iter != parsed_options.end());
+ iter = parsed_options.find("async_clients");
+ async_clients_ = (iter != parsed_options.end());
+
out_dir_base_ = "gen-cocoa";
}
@@ -128,8 +131,17 @@
*/
void generate_cocoa_service_protocol(std::ofstream& out, t_service* tservice);
+ void generate_cocoa_service_async_protocol(std::ofstream& out, t_service* tservice);
+
void generate_cocoa_service_client_interface(std::ofstream& out, t_service* tservice);
+ void generate_cocoa_service_client_async_interface(std::ofstream& out, t_service* tservice);
+
+ void generate_cocoa_service_client_send_function_implementation(ofstream& out, t_function* tfunction);
+ void generate_cocoa_service_client_send_function_invocation(ofstream& out, t_function* tfunction);
+ void generate_cocoa_service_client_recv_function_implementation(ofstream& out, t_function* tfunction);
void generate_cocoa_service_client_implementation(std::ofstream& out, t_service* tservice);
+ void generate_cocoa_service_client_async_implementation(std::ofstream& out, t_service* tservice);
+
void generate_cocoa_service_server_interface(std::ofstream& out, t_service* tservice);
void generate_cocoa_service_server_implementation(std::ofstream& out, t_service* tservice);
void generate_cocoa_service_helpers(t_service* tservice);
@@ -185,6 +197,7 @@
std::string declare_field(t_field* tfield);
std::string declare_property(t_field* tfield);
std::string function_signature(t_function* tfunction);
+ std::string async_function_signature(t_function* tfunction);
std::string argument_list(t_struct* tstruct);
std::string type_to_enum(t_type* ttype);
std::string format_string_for_type(t_type* type);
@@ -212,6 +225,7 @@
bool log_unexpected_;
bool validate_required_;
+ bool async_clients_;
};
/**
@@ -258,9 +272,15 @@
*/
string t_cocoa_generator::cocoa_thrift_imports() {
string result = string() + "#import \"TProtocol.h\"\n" + "#import \"TApplicationException.h\"\n"
- + "#import \"TProtocolException.h\"\n" + "#import \"TProtocolUtil.h\"\n"
- + "#import \"TProcessor.h\"\n" + "#import \"TObjective-C.h\"\n"
- + "#import \"TBase.h\"\n" + "\n";
+ + "#import \"TProtocolException.h\"\n"
+ + "#import \"TProtocolUtil.h\"\n"
+ + "#import \"TProcessor.h\"\n"
+ + "#import \"TObjective-C.h\"\n"
+ + "#import \"TBase.h\"\n"
+ + "#import \"TAsyncTransport.h\"\n"
+ + "#import \"TProtocolFactory.h\"\n"
+ + "#import \"TBaseClient.h\"\n"
+ + "\n";
// Include other Thrift includes
const vector<t_program*>& includes = program_->get_includes();
@@ -1209,6 +1229,11 @@
generate_cocoa_service_helpers(tservice);
generate_cocoa_service_client_implementation(f_impl_, tservice);
generate_cocoa_service_server_implementation(f_impl_, tservice);
+ if(async_clients_) {
+ generate_cocoa_service_async_protocol(f_header_, tservice);
+ generate_cocoa_service_client_async_interface(f_header_, tservice);
+ generate_cocoa_service_client_async_implementation(f_impl_, tservice);
+ }
}
/**
@@ -1294,20 +1319,31 @@
}
/**
+ * Generates an asynchronous service protocol definition.
+ *
+ * @param tservice The service to generate a protocol definition for
+ */
+void t_cocoa_generator::generate_cocoa_service_async_protocol(ofstream& out, t_service* tservice) {
+ out << "@protocol " << cocoa_prefix_ << tservice->get_name() << "Async" << " <NSObject>" << endl;
+
+ vector<t_function*> functions = tservice->get_functions();
+ vector<t_function*>::iterator f_iter;
+ for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+ out << "- " << async_function_signature(*f_iter) << ";" << endl;
+ }
+ out << "@end" << endl << endl;
+}
+
+/**
* Generates a service client interface definition.
*
* @param tservice The service to generate a client interface definition for
*/
void t_cocoa_generator::generate_cocoa_service_client_interface(ofstream& out,
t_service* tservice) {
- out << "@interface " << cocoa_prefix_ << tservice->get_name() << "Client : NSObject <"
+ out << "@interface " << cocoa_prefix_ << tservice->get_name() << "Client : TBaseClient <"
<< cocoa_prefix_ << tservice->get_name() << "> ";
- scope_up(out);
- out << indent() << "id <TProtocol> inProtocol;" << endl;
- out << indent() << "id <TProtocol> outProtocol;" << endl;
- scope_down(out);
-
out << "- (id) initWithProtocol: (id <TProtocol>) protocol;" << endl;
out << "- (id) initWithInProtocol: (id <TProtocol>) inProtocol outProtocol: (id <TProtocol>) "
"outProtocol;" << endl;
@@ -1315,6 +1351,25 @@
}
/**
+ * Generates a service client interface definition.
+ *
+ * @param tservice The service to generate a client interface definition for
+ */
+void t_cocoa_generator::generate_cocoa_service_client_async_interface(ofstream& out,
+ t_service* tservice) {
+ out << "@interface " << cocoa_prefix_ << tservice->get_name() << "ClientAsync : TBaseClient <"
+ << cocoa_prefix_ << tservice->get_name() << "Async> ";
+
+ scope_up(out);
+ out << indent() << "id <TAsyncTransport> asyncTransport;" << endl;
+ scope_down(out);
+
+ out << "- (id) initWithProtocolFactory: (id <TProtocolFactory>) factory "
+ "transport: (id <TAsyncTransport>) transport;" << endl;
+ out << "@end" << endl << endl;
+}
+
+/**
* Generates a service server interface definition. In other words, the TProcess implementation for
*the
* service definition.
@@ -1338,6 +1393,141 @@
out << "@end" << endl << endl;
}
+void t_cocoa_generator::generate_cocoa_service_client_send_function_implementation(ofstream& out,
+ t_function* tfunction) {
+ string funname = tfunction->get_name();
+
+ t_function send_function(g_type_void,
+ string("send_") + tfunction->get_name(),
+ tfunction->get_arglist());
+
+ string argsname = tfunction->get_name() + "_args";
+
+ // Open function
+ indent(out) << "- " << function_signature(&send_function) << endl;
+ scope_up(out);
+
+ // Serialize the request
+ out << indent() << "[outProtocol writeMessageBeginWithName: @\"" << funname << "\""
+ << (tfunction->is_oneway() ? " type: TMessageType_ONEWAY" : " type: TMessageType_CALL")
+ << " sequenceID: 0];" << endl;
+
+ out << indent() << "[outProtocol writeStructBeginWithName: @\"" << argsname << "\"];" << endl;
+
+ // write out function parameters
+ t_struct* arg_struct = tfunction->get_arglist();
+ const vector<t_field*>& fields = arg_struct->get_members();
+ vector<t_field*>::const_iterator fld_iter;
+ for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+ string fieldName = (*fld_iter)->get_name();
+ if (type_can_be_null((*fld_iter)->get_type())) {
+ out << indent() << "if (" << fieldName << " != nil)";
+ scope_up(out);
+ }
+ out << indent() << "[outProtocol writeFieldBeginWithName: @\"" << fieldName
+ << "\""
+ " type: " << type_to_enum((*fld_iter)->get_type())
+ << " fieldID: " << (*fld_iter)->get_key() << "];" << endl;
+
+ generate_serialize_field(out, *fld_iter, fieldName);
+
+ out << indent() << "[outProtocol writeFieldEnd];" << endl;
+
+ if (type_can_be_null((*fld_iter)->get_type())) {
+ indent_down();
+ out << indent() << "}" << endl;
+ }
+ }
+
+ out << indent() << "[outProtocol writeFieldStop];" << endl;
+ out << indent() << "[outProtocol writeStructEnd];" << endl;
+ out << indent() << "[outProtocol writeMessageEnd];" << endl;
+ scope_down(out);
+ out << endl;
+}
+
+void t_cocoa_generator::generate_cocoa_service_client_recv_function_implementation(ofstream& out,
+ t_function* tfunction) {
+ t_struct noargs(program_);
+ t_function recv_function(tfunction->get_returntype(),
+ string("recv_") + tfunction->get_name(),
+ &noargs,
+ tfunction->get_xceptions());
+ // Open function
+ indent(out) << "- " << function_signature(&recv_function) << endl;
+ scope_up(out);
+
+ // TODO(mcslee): Message validation here, was the seqid etc ok?
+
+ // check for an exception
+ out << indent() << "TApplicationException * x = [self checkIncomingMessageException];" << endl
+ << indent() << "if (x != nil)";
+ scope_up(out);
+ out << indent() << "@throw x;" << endl;
+ scope_down(out);
+
+ // FIXME - could optimize here to reduce creation of temporary objects.
+ string resultname = function_result_helper_struct_type(tfunction);
+ out << indent() << cocoa_prefix_ << resultname << " * result = [[[" << cocoa_prefix_
+ << resultname << " alloc] init] autorelease_stub];" << endl;
+ indent(out) << "[result read: inProtocol];" << endl;
+ indent(out) << "[inProtocol readMessageEnd];" << endl;
+
+ // Careful, only return _result if not a void function
+ if (!tfunction->get_returntype()->is_void()) {
+ out << indent() << "if ([result successIsSet]) {" << endl << indent()
+ << " return [result success];" << endl << indent() << "}" << endl;
+ }
+
+ t_struct* xs = tfunction->get_xceptions();
+ const std::vector<t_field*>& xceptions = xs->get_members();
+ vector<t_field*>::const_iterator x_iter;
+ for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+ out << indent() << "if ([result " << (*x_iter)->get_name() << "IsSet]) {" << endl
+ << indent() << " @throw [result " << (*x_iter)->get_name() << "];" << endl << indent()
+ << "}" << endl;
+ }
+
+ // If you get here it's an exception, unless a void function
+ if (tfunction->get_returntype()->is_void()) {
+ indent(out) << "return;" << endl;
+ } else {
+ out << indent() << "@throw [TApplicationException exceptionWithType: "
+ "TApplicationException_MISSING_RESULT" << endl << indent()
+ << " reason: @\"" << tfunction->get_name()
+ << " failed: unknown result\"];" << endl;
+ }
+
+ // Close function
+ scope_down(out);
+ out << endl;
+}
+
+/**
+ * Generates an invocation of a given 'send_' function.
+ *
+ * @param tfunction The service to generate an implementation for
+ */
+void t_cocoa_generator::generate_cocoa_service_client_send_function_invocation(ofstream& out,
+ t_function* tfunction) {
+ t_struct* arg_struct = tfunction->get_arglist();
+ const vector<t_field*>& fields = arg_struct->get_members();
+ vector<t_field*>::const_iterator fld_iter;
+ indent(out) << "[self send_" << tfunction->get_name();
+ bool first = true;
+ for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+ string fieldName = (*fld_iter)->get_name();
+ out << " ";
+ if (first) {
+ first = false;
+ out << ": " << fieldName;
+ } else {
+ out << fieldName << ": " << fieldName;
+ }
+ }
+ out << "];" << endl;
+}
+
/**
* Generates a service client implementation.
*
@@ -1364,12 +1554,54 @@
scope_down(out);
out << endl;
- // dealloc
- out << "- (void) dealloc" << endl;
+ // generate client method implementations
+ vector<t_function*> functions = tservice->get_functions();
+ vector<t_function*>::const_iterator f_iter;
+ for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+
+ generate_cocoa_service_client_send_function_implementation(out, *f_iter);
+
+ if (!(*f_iter)->is_oneway()) {
+ generate_cocoa_service_client_recv_function_implementation(out, *f_iter);
+ }
+
+ // Open function
+ indent(out) << "- " << function_signature(*f_iter) << endl;
+ scope_up(out);
+ generate_cocoa_service_client_send_function_invocation(out, *f_iter);
+
+ out << indent() << "[[outProtocol transport] flush];" << endl;
+ if (!(*f_iter)->is_oneway()) {
+ out << indent();
+ if (!(*f_iter)->get_returntype()->is_void()) {
+ out << "return ";
+ }
+ out << "[self recv_" << (*f_iter)->get_name() << "];" << endl;
+ }
+ scope_down(out);
+ out << endl;
+ }
+ indent_down();
+ out << "@end" << endl << endl;
+}
+
+/**
+ * Generates a service client implementation for its asynchronous interface.
+ *
+ * @param tservice The service to generate an implementation for
+ */
+void t_cocoa_generator::generate_cocoa_service_client_async_implementation(ofstream& out,
+ t_service* tservice) {
+ out << "@implementation " << cocoa_prefix_ << tservice->get_name() << "ClientAsync" << endl << endl
+ << "- (id) initWithProtocolFactory: (id <TProtocolFactory>) factory "
+ "transport: (id <TAsyncTransport>) transport;" << endl;
+
scope_up(out);
- out << indent() << "[inProtocol release_stub];" << endl;
- out << indent() << "[outProtocol release_stub];" << endl;
- out << indent() << "[super dealloc_stub];" << endl;
+ out << indent() << "self = [super init];" << endl;
+ out << indent() << "inProtocol = [[factory newProtocolOnTransport:transport] retain_stub];" << endl;
+ out << indent() << "outProtocol = inProtocol;" << endl;
+ out << indent() << "asyncTransport = transport;" << endl;
+ out << indent() << "return self;" << endl;
scope_down(out);
out << endl;
@@ -1377,147 +1609,61 @@
vector<t_function*> functions = tservice->get_functions();
vector<t_function*>::const_iterator f_iter;
for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
- string funname = (*f_iter)->get_name();
-
- t_function send_function(g_type_void,
- string("send_") + (*f_iter)->get_name(),
- (*f_iter)->get_arglist());
-
- string argsname = (*f_iter)->get_name() + "_args";
-
- // Open function
- indent(out) << "- " << function_signature(&send_function) << endl;
- scope_up(out);
-
- // Serialize the request
- out << indent() << "[outProtocol writeMessageBeginWithName: @\"" << funname << "\""
- << ((*f_iter)->is_oneway() ? " type: TMessageType_ONEWAY" : " type: TMessageType_CALL")
- << " sequenceID: 0];" << endl;
-
- out << indent() << "[outProtocol writeStructBeginWithName: @\"" << argsname << "\"];" << endl;
-
- // write out function parameters
- t_struct* arg_struct = (*f_iter)->get_arglist();
- const vector<t_field*>& fields = arg_struct->get_members();
- vector<t_field*>::const_iterator fld_iter;
- for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
- string fieldName = (*fld_iter)->get_name();
- if (type_can_be_null((*fld_iter)->get_type())) {
- out << indent() << "if (" << fieldName << " != nil)";
- scope_up(out);
- }
- out << indent() << "[outProtocol writeFieldBeginWithName: @\"" << fieldName
- << "\""
- " type: " << type_to_enum((*fld_iter)->get_type())
- << " fieldID: " << (*fld_iter)->get_key() << "];" << endl;
-
- generate_serialize_field(out, *fld_iter, fieldName);
-
- out << indent() << "[outProtocol writeFieldEnd];" << endl;
-
- if (type_can_be_null((*fld_iter)->get_type())) {
- scope_down(out);
- }
- }
-
- out << indent() << "[outProtocol writeFieldStop];" << endl;
- out << indent() << "[outProtocol writeStructEnd];" << endl;
-
- out << indent() << "[outProtocol writeMessageEnd];" << endl << indent()
- << "[[outProtocol transport] flush];" << endl;
-
- scope_down(out);
- out << endl;
+
+ generate_cocoa_service_client_send_function_implementation(out, *f_iter);
if (!(*f_iter)->is_oneway()) {
- t_struct noargs(program_);
- t_function recv_function((*f_iter)->get_returntype(),
- string("recv_") + (*f_iter)->get_name(),
- &noargs,
- (*f_iter)->get_xceptions());
- // Open function
- indent(out) << "- " << function_signature(&recv_function) << endl;
- scope_up(out);
-
- // TODO(mcslee): Message validation here, was the seqid etc ok?
-
- // check for an exception
- out << indent() << "int msgType = 0;" << endl << indent()
- << "[inProtocol readMessageBeginReturningName: nil type: &msgType sequenceID: NULL];"
- << endl << indent() << "if (msgType == TMessageType_EXCEPTION) {" << endl << indent()
- << " TApplicationException * x = [TApplicationException read: inProtocol];" << endl
- << indent() << " [inProtocol readMessageEnd];" << endl << indent() << " @throw x;"
- << endl << indent() << "}" << endl;
-
- // FIXME - could optimize here to reduce creation of temporary objects.
- string resultname = function_result_helper_struct_type(*f_iter);
- out << indent() << cocoa_prefix_ << resultname << " * result = [[[" << cocoa_prefix_
- << resultname << " alloc] init] autorelease_stub];" << endl;
- indent(out) << "[result read: inProtocol];" << endl;
- indent(out) << "[inProtocol readMessageEnd];" << endl;
-
- // Careful, only return _result if not a void function
- if (!(*f_iter)->get_returntype()->is_void()) {
- out << indent() << "if ([result successIsSet]) {" << endl << indent()
- << " return [result success];" << endl << indent() << "}" << endl;
- }
-
- t_struct* xs = (*f_iter)->get_xceptions();
- const std::vector<t_field*>& xceptions = xs->get_members();
- vector<t_field*>::const_iterator x_iter;
- for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
- out << indent() << "if ([result " << (*x_iter)->get_name() << "IsSet]) {" << endl
- << indent() << " @throw [result " << (*x_iter)->get_name() << "];" << endl << indent()
- << "}" << endl;
- }
-
- // If you get here it's an exception, unless a void function
- if ((*f_iter)->get_returntype()->is_void()) {
- indent(out) << "return;" << endl;
- } else {
- out << indent() << "@throw [TApplicationException exceptionWithType: "
- "TApplicationException_MISSING_RESULT" << endl << indent()
- << " reason: @\"" << (*f_iter)->get_name()
- << " failed: unknown result\"];" << endl;
- }
-
- // Close function
- scope_down(out);
- out << endl;
+ generate_cocoa_service_client_recv_function_implementation(out, *f_iter);
}
// Open function
- indent(out) << "- " << function_signature(*f_iter) << endl;
+ indent(out) << "- " << async_function_signature(*f_iter) << endl;
scope_up(out);
- indent(out) << "[self send_" << funname;
+ indent(out) << "@try {" << endl;
+ indent_up();
+ generate_cocoa_service_client_send_function_invocation(out, *f_iter);
+ indent_down();
+ out << indent() << "} @catch(TException * texception) {" << endl;
+ indent_up();
+ out << indent() << "failureBlock(texception);" << endl
+ << indent() << "return;" << endl;
+ indent_down();
+ indent(out) << "}" << endl;
+
+ out << indent() << "[asyncTransport flush:^{" << endl;
+ indent_up();
- // Declare the function arguments
- bool first = true;
- for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
- string fieldName = (*fld_iter)->get_name();
- out << " ";
- if (first) {
- first = false;
- out << ": " << fieldName;
- } else {
- out << fieldName << ": " << fieldName;
- }
- }
- out << "];" << endl;
+ out << indent() << "@try {" << endl;
+ indent_up();
- if (!(*f_iter)->is_oneway()) {
- out << indent();
- if (!(*f_iter)->get_returntype()->is_void()) {
- out << "return ";
- }
- out << "[self recv_" << funname << "];" << endl;
+ string recv_invocation = "[self recv_" + (*f_iter)->get_name() + "]";
+ if (!(*f_iter)->is_oneway() && (*f_iter)->get_returntype()->is_void()) {
+ out << indent() << recv_invocation << ";" << endl;
}
+ out << indent() << "responseBlock(";
+ if (!(*f_iter)->is_oneway() && !(*f_iter)->get_returntype()->is_void()) {
+ out << recv_invocation;
+ }
+ out << ");" << endl;
+
+ indent_down();
+
+ out << indent() << "} @catch(TException * texception) {" << endl;
+ indent_up();
+
+ out << indent() << "failureBlock(texception);" << endl;
+
+ indent_down();
+ out << indent() << "}" << endl;
+
+ indent_down();
+ out << indent() << "} failure:failureBlock];" << endl;
+
scope_down(out);
+
out << endl;
}
- indent_down();
-
out << "@end" << endl << endl;
}
@@ -2563,6 +2709,28 @@
}
/**
+ * Renders a function signature that returns asynchronously instead of
+ * literally returning.
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_cocoa_generator::async_function_signature(t_function* tfunction) {
+ t_type* ttype = tfunction->get_returntype();
+ t_struct* targlist = tfunction->get_arglist();
+ std::string response_param = "dispatch_block_t";
+ if (!ttype->is_void()) {
+ response_param = "void (^)(" + type_name(ttype) + ")";
+ }
+ std::string result = "(void) " + tfunction->get_name()
+ + argument_list(tfunction->get_arglist())
+ + (targlist->get_members().size() ? " response" : "")
+ + ": (" + response_param + ") responseBlock "
+ + "failure : (TAsyncFailureBlock) failureBlock";
+ return result;
+}
+
+/**
* Renders a colon separated list of types and names, suitable for an
* objective-c parameter list
*/
@@ -2683,4 +2851,5 @@
"Cocoa",
" log_unexpected: Log every time an unexpected field ID or type is encountered.\n"
" validate_required:\n"
- " Throws exception if any required field is not set.\n")
+ " Throws exception if any required field is not set.\n"
+ " async_clients: Generate clients which invoke asynchronously via block syntax.\n")
diff --git a/lib/cocoa/src/TBaseClient.h b/lib/cocoa/src/TBaseClient.h
new file mode 100644
index 0000000..12944b1
--- /dev/null
+++ b/lib/cocoa/src/TBaseClient.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 "TProtocol.h"
+#import "TApplicationException.h"
+
+@interface TBaseClient : NSObject {
+ id <TProtocol> inProtocol;
+ id <TProtocol> outProtocol;
+}
+
+- (TApplicationException *)checkIncomingMessageException;
+
+@end
diff --git a/lib/cocoa/src/TBaseClient.m b/lib/cocoa/src/TBaseClient.m
new file mode 100644
index 0000000..d15f9d3
--- /dev/null
+++ b/lib/cocoa/src/TBaseClient.m
@@ -0,0 +1,46 @@
+/*
+ * 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 "TBaseClient.h"
+#import "TApplicationException.h"
+#import "TObjective-C.h"
+
+@implementation TBaseClient
+
+- (void) dealloc
+{
+ [inProtocol release_stub];
+ [outProtocol release_stub];
+ [super dealloc_stub];
+}
+
+- (TApplicationException *)checkIncomingMessageException
+{
+ int msgType = 0;
+ [inProtocol readMessageBeginReturningName: nil type: &msgType sequenceID: NULL];
+ if (msgType == TMessageType_EXCEPTION) {
+ TApplicationException * x = [TApplicationException read: inProtocol];
+ [inProtocol readMessageEnd];
+ return x;
+ }
+
+ return nil;
+}
+
+@end
diff --git a/lib/cocoa/src/transport/TAsyncTransport.h b/lib/cocoa/src/transport/TAsyncTransport.h
new file mode 100644
index 0000000..f75b701
--- /dev/null
+++ b/lib/cocoa/src/transport/TAsyncTransport.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 "TTransport.h"
+#import "TException.h"
+
+typedef void(^TAsyncFailureBlock)(TException *);
+
+@protocol TAsyncTransport <TTransport>
+
+- (void) flush:(dispatch_block_t)flushed failure:(TAsyncFailureBlock)failure;
+
+@end