THRIFT-2709 c_glib: Support server implementation Patch: Simon South
Project: http://git-wip-us.apache.org/repos/asf/thrift/repo Commit: http://git-wip-us.apache.org/repos/asf/thrift/commit/63243c6a Tree: http://git-wip-us.apache.org/repos/asf/thrift/tree/63243c6a Diff: http://git-wip-us.apache.org/repos/asf/thrift/diff/63243c6a Branch: refs/heads/master Commit: 63243c6a2923cfee1d7d7d3b74ba7ccfcd448dc0 Parents: 51ba56c Author: Roger Meier <[email protected]> Authored: Mon Sep 29 20:29:58 2014 +0200 Committer: Roger Meier <[email protected]> Committed: Mon Sep 29 20:29:58 2014 +0200 ---------------------------------------------------------------------- compiler/cpp/src/generate/t_c_glib_generator.cc | 1267 +++++++++++++++++- lib/c_glib/Makefile.am | 10 +- .../processor/thrift_dispatch_processor.c | 142 ++ .../processor/thrift_dispatch_processor.h | 95 ++ .../thrift/c_glib/processor/thrift_processor.c | 5 +- .../thrift/c_glib/processor/thrift_processor.h | 5 +- .../src/thrift/c_glib/server/thrift_server.c | 6 +- .../src/thrift/c_glib/server/thrift_server.h | 4 +- .../thrift/c_glib/server/thrift_simple_server.c | 88 +- .../transport/thrift_buffered_transport.c | 9 + .../thrift_buffered_transport_factory.c | 55 + .../thrift_buffered_transport_factory.h | 86 ++ .../c_glib/transport/thrift_framed_transport.c | 9 + .../transport/thrift_framed_transport_factory.c | 55 + .../transport/thrift_framed_transport_factory.h | 86 ++ .../src/thrift/c_glib/transport/thrift_socket.c | 49 + .../thrift/c_glib/transport/thrift_transport.c | 18 + .../thrift/c_glib/transport/thrift_transport.h | 12 + lib/c_glib/test/Makefile.am | 1 + lib/c_glib/test/testsimpleserver.c | 5 +- lib/c_glib/test/testtransportsocket.c | 102 ++ 21 files changed, 2054 insertions(+), 55 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/thrift/blob/63243c6a/compiler/cpp/src/generate/t_c_glib_generator.cc ---------------------------------------------------------------------- diff --git a/compiler/cpp/src/generate/t_c_glib_generator.cc b/compiler/cpp/src/generate/t_c_glib_generator.cc index dbb8a2a..26c3374 100644 --- a/compiler/cpp/src/generate/t_c_glib_generator.cc +++ b/compiler/cpp/src/generate/t_c_glib_generator.cc @@ -42,6 +42,7 @@ static const string endl = "\n"; // avoid ostream << std::endl flushes /* forward declarations */ string initial_caps_to_underscores(string name); +string underscores_to_initial_caps(string name); string to_upper_case(string name); string to_lower_case(string name); @@ -124,6 +125,7 @@ class t_c_glib_generator : public t_oop_generator { /* helper functions */ bool is_complex_type(t_type *ttype); string type_name(t_type* ttype, bool in_typedef=false, bool is_const=false); + string property_type_name(t_type* ttype, bool in_typedef=false, bool is_const=false); string base_type_name(t_base_type *type); string type_to_enum(t_type *type); string constant_literal(t_type *type, t_const_value *value); @@ -136,7 +138,10 @@ class t_c_glib_generator : public t_oop_generator { /* generation functions */ void generate_const_initializer(string name, t_type *type, t_const_value *value); + void generate_service_helpers(t_service *tservice); void generate_service_client(t_service *tservice); + void generate_service_handler(t_service *tservice); + void generate_service_processor(t_service *tservice); void generate_service_server(t_service *tservice); void generate_object(t_struct *tstruct); void generate_struct_writer(ofstream &out, t_struct *tstruct, string this_name, string this_get="", bool is_function=true); @@ -424,6 +429,9 @@ void t_c_glib_generator::generate_service (t_service *tservice) { // add standard includes f_header_ << + "#include <thrift/c_glib/processor/thrift_dispatch_processor.h>" << endl << + endl; + f_header_ << "#include \"" << this->nspace_lc << program_name_lc << "_types.h\"" << endl; // if we are inheriting from another service, include its header @@ -450,6 +458,9 @@ void t_c_glib_generator::generate_service (t_service *tservice) { "#include \"" << filename << ".h\"" << endl << endl; + // generate the service-helper classes + generate_service_helpers (tservice); + // generate the client objects generate_service_client (tservice); @@ -593,6 +604,41 @@ string t_c_glib_generator::type_name (t_type* ttype, bool in_typedef, bool is_co } /** + * Maps a Thrift primitive to the type needed to hold its value when used as an + * object property. + * + * This method is needed because all integer properties of width less than 64 + * bits map to the same type, gint, as opposed to their width-specific type + * (gint8, gint16 or gint32). + */ +string t_c_glib_generator::property_type_name (t_type* ttype, + bool in_typedef, + bool is_const) { + string result; + + if (ttype->is_base_type()) { + switch (((t_base_type *) ttype)->get_base()) { + case t_base_type::TYPE_BYTE: + case t_base_type::TYPE_I16: + case t_base_type::TYPE_I32: + if (is_const) { + result = "const gint"; + } else { + result = "gint"; + } + break; + + default: + result = type_name(ttype, in_typedef, is_const); + } + } else { + result = type_name(ttype, in_typedef, is_const); + } + + return result; +} + +/** * Maps a Thrift primitive to a C primitive. */ string t_c_glib_generator::base_type_name(t_base_type *type) { @@ -1108,6 +1154,59 @@ void t_c_glib_generator::generate_const_initializer(string name, t_type *type, t } /** + * Generates helper classes for a service, consisting of a ThriftStruct subclass + * for the arguments to and the result from each method. + * + * @param tservice The service for which to generate helper classes + */ +void t_c_glib_generator::generate_service_helpers(t_service *tservice) { + vector<t_function*> functions = tservice->get_functions(); + vector<t_function*>::iterator function_iter; + + // Iterate through the service's methods + for (function_iter = functions.begin(); + function_iter != functions.end(); + ++function_iter) { + string function_name = (*function_iter)->get_name(); + t_struct *arg_list = (*function_iter)->get_arglist(); + string arg_list_name_orig = arg_list->get_name(); + + // Generate the arguments class + arg_list->set_name(tservice->get_name() + + underscores_to_initial_caps(function_name) + + "Args"); + generate_struct(arg_list); + + arg_list->set_name(arg_list_name_orig); + + // Generate the result class + if (!(*function_iter)->is_oneway()) { + t_struct result(program_, + tservice->get_name() + + underscores_to_initial_caps(function_name) + + "Result"); + t_field success((*function_iter)->get_returntype(), "success", 0); + success.set_req(t_field::T_OPTIONAL); + if (!(*function_iter)->get_returntype()->is_void()) { + result.append(&success); + } + + t_struct* xs = (*function_iter)->get_xceptions(); + const vector<t_field*>& fields = xs->get_members(); + vector<t_field*>::const_iterator field_iter; + for (field_iter = fields.begin(); + field_iter != fields.end(); + ++field_iter) { + (*field_iter)->set_req(t_field::T_OPTIONAL); + result.append(*field_iter); + } + + generate_struct(&result); + } + } +} + +/** * Generates C code that represents a Thrift service client. */ void t_c_glib_generator::generate_service_client(t_service *tservice) { @@ -1792,16 +1891,1135 @@ void t_c_glib_generator::generate_service_client(t_service *tservice) { } /** + * Generates C code that represents a Thrift service handler. + * + * @param tservice The service for which to generate a handler. + */ +void t_c_glib_generator::generate_service_handler(t_service *tservice) { + vector<t_function*> functions = tservice->get_functions(); + vector<t_function*>::const_iterator function_iter; + + string service_name_lc = + to_lower_case(initial_caps_to_underscores(service_name_)); + string service_name_uc = to_upper_case(service_name_lc); + + string class_name = this->nspace + service_name_ + "Handler"; + string class_name_lc = + to_lower_case(initial_caps_to_underscores(class_name)); + string class_name_uc = to_upper_case(class_name_lc); + + string parent_class_name; + string parent_type_name; + + string args_indent; + + // The service this service extends, or NULL if it extends no service + t_service *extends_service = tservice->get_extends(); + + // Determine the name of our parent service (if any) and the handler class' + // parent class name and type + if (extends_service) { + string parent_service_name = extends_service->get_name(); + string parent_service_name_lc = + to_lower_case(initial_caps_to_underscores(parent_service_name)); + string parent_service_name_uc = to_upper_case(parent_service_name_lc); + + parent_class_name = + this->nspace + parent_service_name + "Handler"; + parent_type_name = + this->nspace_uc + "TYPE_" + parent_service_name_uc + "_HANDLER"; + } + else { + parent_class_name = "GObject"; + parent_type_name = "G_TYPE_OBJECT"; + } + + // Generate the handler class' definition in the header file + + // Generate the handler instance definition + f_header_ << + "/* " << service_name_ << " handler (abstract base class) */" << endl << + "struct _" << class_name << endl << + "{" << endl; + indent_up(); + f_header_ << + indent() << parent_class_name << " parent;" << endl; + indent_down(); + f_header_ << + "};" << endl << + "typedef struct _" << class_name << " " << class_name << ";" << endl << + endl; + + // Generate the handler class definition, including its class members + // (methods) + f_header_ << + "struct _" << class_name << "Class" << endl << + "{" << endl; + indent_up(); + f_header_ << + indent() << parent_class_name << "Class parent;" << endl << + endl; + + for (function_iter = functions.begin(); + function_iter != functions.end(); + ++function_iter) { + string method_name = + initial_caps_to_underscores((*function_iter)->get_name()); + t_type *return_type = (*function_iter)->get_returntype(); + t_struct *arg_list = (*function_iter)->get_arglist(); + t_struct *x_list = (*function_iter)->get_xceptions(); + bool has_return = !return_type->is_void(); + bool has_args = arg_list->get_members().size() == 0; + bool has_xceptions = x_list->get_members().size() == 0; + + string params = "(" + this->nspace + service_name_ + "If *iface" + + (has_return ? ", " + type_name (return_type) + "* _return" : "") + + (has_args ? "" : (", " + argument_list (arg_list))) + + (has_xceptions ? "" : (", " + xception_list (x_list))) + + ", GError **error)"; + + indent(f_header_) << "gboolean (*" << method_name << ") " << params << ";" << + endl; + } + indent_down(); + + f_header_ << + "};" << endl << + "typedef struct _" << class_name << "Class " << class_name << "Class;" << endl << + endl; + + // Generate the remaining header boilerplate + f_header_ << + "GType " << class_name_lc << "_get_type (void);" << endl << + "#define " << this->nspace_uc << "TYPE_" << service_name_uc << "_HANDLER " << + "(" << class_name_lc << "_get_type())" << endl << + "#define " << class_name_uc << "(obj) " << + "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << + this->nspace_uc << "TYPE_" << service_name_uc << "_HANDLER, " << + class_name << "))" << endl << + "#define " << this->nspace_uc << "IS_" << service_name_uc << "_HANDLER(obj) " << + "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << + this->nspace_uc << "TYPE_" << service_name_uc << "_HANDLER))" << endl << + "#define " << class_name_uc << "_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), " << + this->nspace_uc << "TYPE_" << service_name_uc << "_HANDLER, " << + class_name << "Class))" << endl << + "#define " << this->nspace_uc << "IS_" << service_name_uc << + "_HANDLER_CLASS(c) " << "(G_TYPE_CHECK_CLASS_TYPE ((c), " << + this->nspace_uc << "TYPE_" << service_name_uc << "_HANDLER))" << endl << + "#define " << this->nspace_uc << service_name_uc << + "_HANDLER_GET_CLASS(obj) " << "(G_TYPE_INSTANCE_GET_CLASS ((obj), " << + this->nspace_uc << "TYPE_" << service_name_uc << "_HANDLER, " << + class_name << "Class))" << endl << + endl; + + // Generate the handler class' method definitions + for (function_iter = functions.begin(); + function_iter != functions.end(); + ++function_iter) { + string method_name = + initial_caps_to_underscores((*function_iter)->get_name()); + t_type *return_type = (*function_iter)->get_returntype(); + t_struct *arg_list = (*function_iter)->get_arglist(); + t_struct *x_list = (*function_iter)->get_xceptions(); + bool has_return = !return_type->is_void(); + bool has_args = arg_list->get_members().size() == 0; + bool has_xceptions = x_list->get_members().size() == 0; + + string params = "(" + this->nspace + service_name_ + "If *iface" + + (has_return ? ", " + type_name (return_type) + "* _return" : "") + + (has_args ? "" : (", " + argument_list (arg_list))) + + (has_xceptions ? "" : (", " + xception_list (x_list))) + + ", GError **error)"; + + f_header_ << "gboolean " << class_name_lc << "_" << method_name << " " << + params << ";" << endl; + } + f_header_ << endl; + + // Generate the handler's implementation in the implementation file + + // Generate the implementation boilerplate + f_service_ << + "static void" << endl << + class_name_lc << "_" << service_name_lc << "_if_interface_init (" << + this->nspace << service_name_ << "IfInterface *iface);" << endl << + endl; + + args_indent = string (25, ' '); + f_service_ << + "G_DEFINE_TYPE_WITH_CODE (" << class_name << ", " << endl << + args_indent << class_name_lc << "," << endl << + args_indent << parent_type_name << "," << endl << + args_indent << "G_IMPLEMENT_INTERFACE (" << + this->nspace_uc << "TYPE_" << service_name_uc << "_IF," << endl; + args_indent += string (23, ' '); + f_service_ << + args_indent << class_name_lc << "_" << service_name_lc << + "_if_interface_init));" << endl << + endl; + + // Generate the handler method implementations + for (function_iter = functions.begin(); + function_iter != functions.end(); + ++function_iter) { + string function_name = (*function_iter)->get_name(); + string method_name = initial_caps_to_underscores(function_name); + t_type *return_type = (*function_iter)->get_returntype(); + t_struct *arg_list = (*function_iter)->get_arglist(); + t_struct *x_list = (*function_iter)->get_xceptions(); + + const vector<t_field*>& args = arg_list->get_members(); + const vector<t_field*>& xceptions = x_list->get_members(); + + vector<t_field*>::const_iterator field_iter; + + t_function + implementing_function (return_type, + service_name_lc + "_handler_" + method_name, + arg_list, + x_list, + (*function_iter)->is_oneway()); + + indent(f_service_) << + function_signature (&implementing_function) << endl; + scope_up(f_service_); + f_service_ << + indent() << "g_return_if_fail (" << + this->nspace_uc << "IS_" << service_name_uc << "_HANDLER (iface));" << endl << + endl << + indent() << class_name_uc << "_GET_CLASS (iface)" << "->" << method_name << + " (iface, "; + + if(!return_type->is_void()) { + f_service_ << "_return, "; + } + for (field_iter = args.begin(); + field_iter != args.end(); + ++field_iter) { + f_service_ << (*field_iter)->get_name() << ", "; + } + for (field_iter = xceptions.begin(); + field_iter != xceptions.end(); + ++field_iter) { + f_service_ << (*field_iter)->get_name() << ", "; + } + f_service_ << "error);" << endl; + scope_down(f_service_); + f_service_ << endl; + } + + // Generate the handler interface initializer + f_service_ << + "static void" << endl << + class_name_lc << "_" << service_name_lc << "_if_interface_init (" << + this->nspace << service_name_ << "IfInterface *iface)" << endl; + scope_up(f_service_); + for (function_iter = functions.begin(); + function_iter != functions.end(); + ++function_iter) { + string method_name = + initial_caps_to_underscores((*function_iter)->get_name()); + + f_service_ << + indent() << "iface->" << method_name << " = " << + class_name_lc << "_" << method_name << ";" << endl; + } + scope_down(f_service_); + f_service_ << endl; + + // Generate the handler instance initializer + f_service_ << + "static void" << endl << + class_name_lc << "_init (" << class_name << " *self)" << endl; + scope_up(f_service_); + f_service_ << + indent() << "THRIFT_UNUSED_VAR (self);" << endl; + scope_down(f_service_); + f_service_ << endl; + + // Generate the handler class initializer + f_service_ << + "static void" << endl << + class_name_lc << "_class_init (" << class_name << "Class *cls)" << endl; + scope_up(f_service_); + for (function_iter = functions.begin(); + function_iter != functions.end(); + ++function_iter) { + string function_name = (*function_iter)->get_name(); + string method_name = initial_caps_to_underscores(function_name); + + // All methods are pure virtual and must be implemented by subclasses + f_service_ << + indent() << "cls->" << method_name << " = NULL;" << endl; + } + scope_down(f_service_); + f_service_ << endl; +} + +/** + * Generates C code that represents a Thrift service processor. + * + * @param tservice The service for which to generate a processor + */ +void t_c_glib_generator::generate_service_processor(t_service *tservice) { + vector<t_function*> functions = tservice->get_functions(); + vector<t_function*>::const_iterator function_iter; + + string service_name_lc = + to_lower_case(initial_caps_to_underscores(service_name_)); + string service_name_uc = to_upper_case(service_name_lc); + + string class_name = this->nspace + service_name_ + "Processor"; + string class_name_lc = + to_lower_case(initial_caps_to_underscores(class_name)); + string class_name_uc = to_upper_case(class_name_lc); + + string parent_class_name; + string parent_type_name; + + string handler_class_name = + this->nspace + service_name_ + "Handler"; + string handler_class_name_lc = + initial_caps_to_underscores(handler_class_name); + + string function_name; + string args_indent; + + // The service this service extends, or NULL if it extends no service + t_service *extends_service = tservice->get_extends(); + + // Determine the name of our parent service (if any) and the + // processor class' parent class name and type + if (extends_service) { + string parent_service_name = extends_service->get_name(); + string parent_service_name_lc = + to_lower_case(initial_caps_to_underscores(parent_service_name)); + string parent_service_name_uc = to_upper_case(parent_service_name_lc); + + parent_class_name = + this->nspace + parent_service_name + "Processor"; + parent_type_name = + this->nspace_uc + "TYPE_" + parent_service_name_uc + "_PROCESSOR"; + } + else { + parent_class_name = "ThriftDispatchProcessor"; + parent_type_name = "THRIFT_TYPE_DISPATCH_PROCESSOR"; + } + + // Generate the processor class' definition in the header file + + // Generate the processor instance definition + f_header_ << + "/* " << service_name_ << " processor */" << endl << + "struct _" << class_name << endl << + "{" << endl; + indent_up(); + f_header_ << + indent() << parent_class_name << " parent;" << endl << + endl << + indent() << "/* protected */" << endl << + indent() << this->nspace + service_name_ + "Handler *handler;" << endl << + indent() << "GHashTable *process_map;" << endl; + indent_down(); + f_header_ << + "};" << endl << + "typedef struct _" << class_name << " " << class_name << ";" << endl << + endl; + + // Generate the processor class definition + f_header_ << + "struct _" << class_name << "Class" << endl << + "{" << endl; + indent_up(); + f_header_ << + indent() << parent_class_name << "Class parent;" << endl << + endl << + indent() << "/* protected */" << endl << + indent() << + "gboolean (*dispatch_call) (ThriftDispatchProcessor *processor," << endl; + args_indent = indent() + string(27, ' '); + f_header_ << + args_indent << "ThriftProtocol *in," << endl << + args_indent << "ThriftProtocol *out," << endl << + args_indent << "gchar *fname," << endl << + args_indent << "gint32 seqid," << endl << + args_indent << "GError **error);" << endl; + indent_down(); + f_header_ << + "};" << endl << + "typedef struct _" << class_name << "Class " << class_name << "Class;" << endl << + endl; + + // Generate the remaining header boilerplate + f_header_ << + "GType " << class_name_lc << "_get_type (void);" << endl << + "#define " << this->nspace_uc << "TYPE_" << service_name_uc << "_PROCESSOR " << + "(" << class_name_lc << "_get_type())" << endl << + "#define " << class_name_uc << "(obj) " << + "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << + this->nspace_uc << "TYPE_" << service_name_uc << "_PROCESSOR, " << + class_name << "))" << endl << + "#define " << this->nspace_uc << "IS_" << service_name_uc << "_PROCESSOR(obj) " << + "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << + this->nspace_uc << "TYPE_" << service_name_uc << "_PROCESSOR))" << endl << + "#define " << class_name_uc << "_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), " << + this->nspace_uc << "TYPE_" << service_name_uc << "_PROCESSOR, " << + class_name << "Class))" << endl << + "#define " << this->nspace_uc << "IS_" << service_name_uc << + "_PROCESSOR_CLASS(c) " << "(G_TYPE_CHECK_CLASS_TYPE ((c), " << + this->nspace_uc << "TYPE_" << service_name_uc << "_PROCESSOR))" << endl << + "#define " << this->nspace_uc << service_name_uc << + "_PROCESSOR_GET_CLASS(obj) " << "(G_TYPE_INSTANCE_GET_CLASS ((obj), " << + this->nspace_uc << "TYPE_" << service_name_uc << "_PROCESSOR, " << + class_name << "Class))" << endl << + endl; + + // Generate the processor's implementation in the implementation file + + // Generate the processor's properties enum + f_service_ << + "enum _" << class_name << "Properties" << endl << + "{" << endl; + indent_up(); + f_service_ << + indent() << "PROP_" << class_name_uc << "_0," << endl << + indent() << "PROP_" << class_name_uc << "_HANDLER" << endl; + indent_down(); + f_service_ << + "};" << endl << + endl; + + // Generate the implementation boilerplate + args_indent = string(15, ' '); + f_service_ << + "G_DEFINE_TYPE (" << class_name << "," << endl << + args_indent << class_name_lc << "," << endl << + args_indent << parent_type_name << ");" << endl << + endl; + + // Generate the processor's processing-function type + function_name = class_name + "ProcessFunction"; + args_indent = string(function_name.length() + 23, ' '); + f_service_ << + "typedef gboolean (* " << function_name << ") (" << + class_name << " *, " << endl << + args_indent << "gint32," << endl << + args_indent << "ThriftProtocol *," << endl << + args_indent << "ThriftProtocol *," << endl << + args_indent << "GError **);" << endl << + endl; + + // Generate the processor's processing functions + for (function_iter = functions.begin(); + function_iter != functions.end(); + ++function_iter) { + string service_function_name = (*function_iter)->get_name(); + string service_function_name_ic = + underscores_to_initial_caps(service_function_name); + string service_function_name_lc = + initial_caps_to_underscores(service_function_name); + string service_function_name_uc = + to_upper_case(service_function_name_lc); + + t_type *return_type = (*function_iter)->get_returntype(); + bool has_return_value = !return_type->is_void(); + + t_struct *arg_list = (*function_iter)->get_arglist(); + const vector<t_field*>& args = arg_list->get_members(); + vector<t_field*>::const_iterator arg_iter; + + const vector<t_field*>& xceptions = + (*function_iter)->get_xceptions()->get_members(); + vector<t_field*>::const_iterator xception_iter; + + string args_class_name = + this->nspace + service_name_ + service_function_name_ic + "Args"; + string args_class_type = + this->nspace_uc + "TYPE_" + service_name_uc + "_" + + service_function_name_uc + "_ARGS"; + + string result_class_name = + this->nspace + service_name_ + service_function_name_ic + "Result"; + string result_class_type = + this->nspace_uc + "TYPE_" + service_name_uc + "_" + + service_function_name_uc + "_RESULT"; + + string handler_function_name = + handler_class_name_lc + "_" + service_function_name_lc; + + function_name = + class_name_lc + + "_process_" + + initial_caps_to_underscores(service_function_name); + + args_indent = string(function_name.length() + 2, ' '); + f_service_ << + "static gboolean" << endl << + function_name << " (" << class_name << " *self," << endl << + args_indent << "gint32 sequence_id," << endl << + args_indent << "ThriftProtocol *input_protocol," << endl << + args_indent << "ThriftProtocol *output_protocol," << endl << + args_indent << "GError **error)" << endl; + scope_up(f_service_); + f_service_ << + indent() << "gboolean result = TRUE;" << endl << + indent() << "ThriftTransport * transport;" << endl << + indent() << args_class_name + " * args =" << endl; + indent_up(); + f_service_ << + indent() << "g_object_new (" << args_class_type << ", NULL);" << endl << + endl; + indent_down(); + if ((*function_iter)->is_oneway()) { + f_service_ << + indent() << "THRIFT_UNUSED_VAR (sequence_id);" << endl << + indent() << "THRIFT_UNUSED_VAR (output_protocol);" << endl << + endl; + } + f_service_ << + indent() << "g_object_get (input_protocol, \"transport\", " << + "&transport, NULL);" << endl << + endl; + + // Read the method's arguments from the caller + f_service_ << + indent() << "if ((thrift_struct_read (THRIFT_STRUCT (args), " << + "input_protocol, error) != -1) &&" << endl << + indent() << " (thrift_protocol_read_message_end (input_protocol, " << + "error) != -1) &&" << endl << + indent() << " (thrift_transport_read_end (transport, error) != FALSE))" << endl; + scope_up(f_service_); + + for (arg_iter = args.begin(); arg_iter != args.end(); ++arg_iter) { + f_service_ << + indent() << property_type_name((*arg_iter)->get_type()) << " " << + (*arg_iter)->get_name() << ";" << endl; + } + for (xception_iter = xceptions.begin(); + xception_iter != xceptions.end(); + ++xception_iter) { + f_service_ << + indent() << type_name((*xception_iter)->get_type()) << " " << + initial_caps_to_underscores((*xception_iter)->get_name()) << + " = NULL;" << + endl; + } + if (has_return_value) { + f_service_ << + indent() << property_type_name(return_type) << " return_value;" << endl; + } + if (!(*function_iter)->is_oneway()) { + f_service_ << + indent() << result_class_name << " * result_struct;" << endl; + } + f_service_ << endl; + + if (args.size() > 0) { + f_service_ << + indent() << "g_object_get (args," << endl; + args_indent = indent() + string(14, ' '); + for (arg_iter = args.begin(); arg_iter != args.end(); ++arg_iter) { + string arg_name = (*arg_iter)->get_name(); + + f_service_ << + args_indent << "\"" << arg_name << "\", &" << arg_name << "," << endl; + } + f_service_ << + args_indent << "NULL);" << endl << + endl; + } + + if (!(*function_iter)->is_oneway()) { + f_service_ << + indent() << "g_object_unref (transport);" << endl << + indent() << "g_object_get (output_protocol, \"transport\", " << + "&transport, NULL);" << endl << + endl << + indent() << "result_struct = g_object_new (" << result_class_type << + ", NULL);" << endl; + if (has_return_value) { + f_service_ << + indent() << "g_object_get (result_struct, " + "\"success\", &return_value, NULL);" << endl; + } + f_service_ << + endl; + } + + // Pass the arguments to the corresponding method in the handler + f_service_ << + indent() << "if (" << handler_function_name << " (" << + this->nspace_uc << service_name_uc << "_IF (self->handler)," << endl; + args_indent = indent() + string(handler_function_name.length() + 6, ' '); + if (has_return_value) { + string return_type_name = type_name(return_type); + + f_service_ << + args_indent; + + // Cast return_value if it was declared as a type other than the return + // value's actual type---this is true for integer values 32 bits or fewer + // in width, for which GLib requires a plain gint type be used when + // storing or retrieving as an object property + if (return_type_name != property_type_name(return_type)) { + if (return_type_name[return_type_name.length() - 1] != '*') { + return_type_name += ' '; + } + return_type_name += '*'; + + f_service_ << + "(" << return_type_name << ")"; + } + + f_service_ << + "&return_value," << endl; + } + for (arg_iter = args.begin(); arg_iter != args.end(); ++arg_iter) { + f_service_ << + args_indent << (*arg_iter)->get_name() << "," << endl; + } + for (xception_iter = xceptions.begin(); + xception_iter != xceptions.end(); + ++xception_iter) { + f_service_ << + args_indent << "&" << + initial_caps_to_underscores((*xception_iter)->get_name()) << "," << endl; + } + f_service_ << + args_indent << "error) == TRUE)" << endl; + scope_up(f_service_); + + // The handler reported success; return the result, if any, to the caller + if (!(*function_iter)->is_oneway()) { + if (has_return_value) { + f_service_ << + indent() << "g_object_set (result_struct, \"success\", return_value, " << + "NULL);" << endl; + + // Deallocate (or unref) return_value + return_type = get_true_type(return_type); + if (return_type->is_base_type()) { + t_base_type *base_type = ((t_base_type *) return_type); + + if (base_type->get_base() == t_base_type::TYPE_STRING) { + f_service_ << + indent() << "if (return_value != NULL)" << endl; + indent_up(); + if (base_type->is_binary()) { + f_service_ << + indent() << "g_byte_array_unref (return_value);" << endl; + } else { + f_service_ << + indent() << "g_free (return_value);" << endl; + } + indent_down(); + } + } else if (return_type->is_container()) { + f_service_ << + indent() << "if (return_value != NULL)" << endl; + indent_up(); + + if (return_type->is_list()) { + f_service_ << + indent() << "g_array_unref (return_value);" << endl; + } else if (return_type->is_map() || return_type->is_set()) { + f_service_ << + indent() << "g_hash_table_unref (return_value);" << endl; + } + + indent_down(); + } else if (return_type->is_struct()) { + f_service_ << + indent() << "if (return_value != NULL)" << endl; + indent_up(); + f_service_ << + indent() << "g_object_unref (return_value);" << endl; + indent_down(); + } + + f_service_ << + endl; + } + f_service_ << + indent() << "result =" << endl; + indent_up(); + f_service_ << + indent() << "((thrift_protocol_write_message_begin (output_protocol," << endl; + args_indent = indent() + string(39, ' '); + f_service_ << + args_indent << "\"" << service_function_name << "\"," << endl << + args_indent << "T_REPLY," << endl << + args_indent << "sequence_id," << endl << + args_indent << "error) != -1) &&" << endl << + indent() << " (thrift_struct_write (THRIFT_STRUCT (result_struct)," << endl; + args_indent = indent() + string(23, ' '); + f_service_ << + args_indent << "output_protocol," << endl << + args_indent << "error) != -1));" << endl; + indent_down(); + } + scope_down(f_service_); + f_service_ << + indent() << "else" << endl; + scope_up(f_service_); + + // The handler reported failure; check to see if an application-defined + // exception was raised and if so, return it to the caller + f_service_ << indent(); + if (xceptions.size() > 0) { + for (xception_iter = xceptions.begin(); + xception_iter != xceptions.end(); + ++xception_iter) { + f_service_ << + "if (" << initial_caps_to_underscores((*xception_iter)->get_name()) << + " != NULL)" << endl; + scope_up(f_service_); + f_service_ << + indent() << "g_object_set (result_struct," << endl; + args_indent = indent() + string(14, ' '); + f_service_ << + args_indent << "\"" << (*xception_iter)->get_name() << "\", " << + (*xception_iter)->get_name() << "," << endl << + args_indent << "NULL);" << endl << + endl; + f_service_ << + indent() << "result =" << endl; + indent_up(); + f_service_ << + indent() << "((thrift_protocol_write_message_begin (output_protocol," << endl; + args_indent = indent() + string(39, ' '); + f_service_ << + args_indent << "\"" << service_function_name << "\"," << endl << + args_indent << "T_REPLY," << endl << + args_indent << "sequence_id," << endl << + args_indent << "error) != -1) &&" << endl << + indent() << " (thrift_struct_write (THRIFT_STRUCT (result_struct)," << endl; + args_indent = indent() + string(23, ' '); + f_service_ << + args_indent << "output_protocol," << endl << + args_indent << "error) != -1));" << endl; + indent_down(); + scope_down(f_service_); + f_service_ << + indent() << "else" << endl; + } + + scope_up(f_service_); + f_service_ << indent(); + } + + // If the handler reported failure but raised no application-defined + // exception, return a Thrift application exception with the information + // returned via GLib's own error-reporting mechanism + f_service_ << + "if (*error == NULL)" << endl; + indent_up(); + f_service_ << + indent() << "g_warning (\"" << service_name_ << "." << + (*function_iter)->get_name() << " implementation returned FALSE \"" << endl << + indent() << string (11, ' ') << "\"but did not set an error\");" << endl << + endl; + indent_down(); + f_service_ << + indent() << "ThriftApplicationException *xception =" << endl; + indent_up(); + f_service_ << + indent() << "g_object_new (THRIFT_TYPE_APPLICATION_EXCEPTION," << endl; + args_indent = indent() + string(14, ' '); + f_service_ << + args_indent << "\"type\", *error != NULL ? (*error)->code :" << endl << + args_indent << string(11, ' ') << "THRIFT_APPLICATION_EXCEPTION_ERROR_UNKNOWN," << endl << + args_indent << "\"message\", *error != NULL ? (*error)->message : NULL," << endl << + args_indent << "NULL);" << endl; + indent_down(); + f_service_ << + indent() << "g_clear_error (error);" << endl << + endl << + indent() << "result =" << endl; + indent_up(); + f_service_ << + indent() << "((thrift_protocol_write_message_begin (output_protocol," << endl; + args_indent = indent() + string(39, ' '); + f_service_ << + args_indent << "\"" << service_function_name << "\"," << endl << + args_indent << "T_EXCEPTION," << endl << + args_indent << "sequence_id," << endl << + args_indent << "error) != -1) &&" << endl << + indent() << " (thrift_struct_write (THRIFT_STRUCT (xception)," << endl; + args_indent = indent() + string(23, ' '); + f_service_ << + args_indent << "output_protocol," << endl << + args_indent << "error) != -1));" << endl; + indent_down(); + f_service_ << + endl << + indent() << "g_object_unref (xception);" << endl; + + if (xceptions.size() > 0) { + scope_down(f_service_); + } + scope_down(f_service_); + f_service_ << endl; + + // Dellocate or unref retrieved argument values as necessary + for (arg_iter = args.begin(); arg_iter != args.end(); ++arg_iter) { + string arg_name = (*arg_iter)->get_name(); + t_type *arg_type = get_true_type((*arg_iter)->get_type()); + + if (arg_type->is_base_type()) { + t_base_type *base_type = ((t_base_type *) arg_type); + + if (base_type->get_base() == t_base_type::TYPE_STRING) { + f_service_ << + indent() << "if (" << arg_name << " != NULL)" << endl; + indent_up(); + if (base_type->is_binary()) { + f_service_ << + indent() << "g_byte_array_unref (" << arg_name << ");" << endl; + } else { + f_service_ << + indent() << "g_free (" << arg_name << ");" << endl; + } + indent_down(); + } + } else if (arg_type->is_container()) { + f_service_ << + indent() << "if (" << arg_name << " != NULL)" << endl; + indent_up(); + + if (arg_type->is_list()) { + f_service_ << + indent() << "g_array_unref (" << arg_name << ");" << endl; + } else if (arg_type->is_map() || arg_type->is_set()) { + f_service_ << + indent() << "g_hash_table_unref (" << arg_name << ");" << endl; + } + + indent_down(); + } else if (arg_type->is_struct()) { + f_service_ << + indent() << "if (" << arg_name << " != NULL)" << endl; + indent_up(); + f_service_ << + indent() << "g_object_unref (" << arg_name << ");" << endl; + indent_down(); + } + } + + if(!(*function_iter)->is_oneway()) { + f_service_ << + indent() << "g_object_unref (result_struct);" << endl << + endl << + indent() << "if (result == TRUE)" << endl; + indent_up(); + f_service_ << + indent() << "result =" << endl; + indent_up(); + f_service_ << + indent() << "((thrift_protocol_write_message_end " << + "(output_protocol, error) != -1) &&" << endl << + indent() << " (thrift_transport_write_end (transport, error) " << + "!= FALSE) &&" << endl << + indent() << " (thrift_transport_flush (transport, error) " << + "!= FALSE));" << endl; + indent_down(); + indent_down(); + } + scope_down(f_service_); + f_service_ << + indent() << "else" << endl; + indent_up(); + f_service_ << + indent() << "result = FALSE;" << endl; + indent_down(); + + f_service_ << + endl << + indent() << "g_object_unref (transport);" << endl << + indent() << "g_object_unref (args);" << endl << + endl << + indent() << "return result;" << endl; + scope_down(f_service_); + + f_service_ << endl; + } + + // Generate the processor's dispatch_call implementation + function_name = class_name_lc + "_dispatch_call"; + args_indent = indent() + string(function_name.length() + 2, ' '); + f_service_ << + "static gboolean" << endl << + function_name << " (ThriftDispatchProcessor *dispatch_processor," << endl << + args_indent << "ThriftProtocol *input_protocol," << endl << + args_indent << "ThriftProtocol *output_protocol," << endl << + args_indent << "gchar *method_name," << endl << + args_indent << "gint32 sequence_id," << endl << + args_indent << "GError **error)" << endl; + scope_up(f_service_); + f_service_ << + indent() << class_name << "ProcessFunction process_function; " << endl; + f_service_ << + indent() << "gboolean dispatch_result = FALSE;" << endl << + endl << + indent() << class_name << " *self = " << + class_name_uc << " (dispatch_processor);" << endl; + f_service_ << + indent() << parent_class_name << "Class " + "*parent_class =" << endl; + indent_up(); + f_service_ << + indent() << "g_type_class_peek_parent (" << class_name_uc << + "_GET_CLASS (self));" << endl; + indent_down(); + f_service_ << + endl << + indent() << "process_function = g_hash_table_lookup (" << + "self->process_map, method_name);" << endl << + indent() << "if (process_function != NULL)" << endl; + scope_up(f_service_); + args_indent = indent() + string(39, ' '); + f_service_ << + indent() << "dispatch_result = (*process_function) (self," << endl << + args_indent << "sequence_id," << endl << + args_indent << "input_protocol," << endl << + args_indent << "output_protocol," << endl << + args_indent << "error);" << endl; + scope_down(f_service_); + f_service_ << + indent() << "else" << endl; + scope_up(f_service_); + + // Method name not recognized; chain up to our parent processor---note the + // top-most implementation of this method, in ThriftDispatchProcessor itself, + // will return an application exception to the caller if no class in the + // hierarchy recognizes the method name + f_service_ << + indent() << "dispatch_result = parent_class->dispatch_call " + "(dispatch_processor," << endl; + args_indent = indent() + string(47, ' '); + f_service_ << + args_indent << "input_protocol," << endl << + args_indent << "output_protocol," << endl << + args_indent << "method_name," << endl << + args_indent << "sequence_id," << endl << + args_indent << "error);" << endl; + scope_down(f_service_); + f_service_ << + endl << + indent() << "return dispatch_result;" << endl; + scope_down(f_service_); + f_service_ << endl; + + // Generate the processor's property setter + function_name = class_name_lc + "_set_property"; + args_indent = string(function_name.length() + 2, ' '); + f_service_ << + "static void" << endl << + function_name << " (GObject *object," << endl << + args_indent << "guint property_id," << endl << + args_indent << "const GValue *value," << endl << + args_indent << "GParamSpec *pspec)" << endl; + scope_up(f_service_); + f_service_ << + indent() << class_name << " *self = " << + class_name_uc << " (object);" << endl << + endl << + indent() << "switch (property_id)" << endl; + scope_up(f_service_); + f_service_ << + indent() << "case PROP_" << class_name_uc << "_HANDLER:" << endl; + indent_up(); + f_service_ << + indent() << "if (self->handler != NULL)" << endl; + indent_up(); + f_service_ << + indent() << "g_object_unref (self->handler);" << endl; + indent_down(); + f_service_ << + indent() << "self->handler = g_value_get_object (value);" << endl << + indent() << "g_object_ref (self->handler);" << endl; + if (extends_service) { + // Chain up to set the handler in every superclass as well + f_service_ << + endl << + indent() << "G_OBJECT_CLASS (" << class_name_lc << "_parent_class)->" << endl; + indent_up(); + f_service_ << + indent() << "set_property (object, property_id, value, pspec);" << endl; + indent_down(); + } + f_service_ << + indent() << "break;" << endl; + indent_down(); + f_service_ << + indent() << "default:" << endl; + indent_up(); + f_service_ << + indent() << + "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);" << endl << + indent() << "break;" << endl; + indent_down(); + scope_down(f_service_); + scope_down(f_service_); + f_service_ << endl; + + // Generate processor's property getter + function_name = class_name_lc + "_get_property"; + args_indent = string(function_name.length() + 2, ' '); + f_service_ << + "static void" << endl << + function_name << " (GObject *object," << endl << + args_indent << "guint property_id," << endl << + args_indent << "GValue *value," << endl << + args_indent << "GParamSpec *pspec)" << endl; + scope_up(f_service_); + f_service_ << + indent() << class_name << " *self = " << + class_name_uc << " (object);" << endl << + endl << + indent() << "switch (property_id)" << endl; + scope_up(f_service_); + f_service_ << + indent() << "case PROP_" << class_name_uc << "_HANDLER:" << endl; + indent_up(); + f_service_ << + indent() << "g_value_set_object (value, self->handler);" << endl << + indent() << "break;" << endl; + indent_down(); + f_service_ << + indent() << "default:" << endl; + indent_up(); + f_service_ << + indent() << + "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);" << endl << + indent() << "break;" << endl; + indent_down(); + scope_down(f_service_); + scope_down(f_service_); + f_service_ << endl; + + // Generator the processor's dispose function + f_service_ << + "static void" << endl << + class_name_lc << "_dispose (GObject *gobject)" << endl; + scope_up(f_service_); + f_service_ << + indent() << class_name << " *self = " << class_name_uc << " (gobject);" << endl << + endl << + indent() << "if (self->handler != NULL)" << endl; + scope_up(f_service_); + f_service_ << + indent() << "g_object_unref (self->handler);" << endl << + indent() << "self->handler = NULL;" << endl; + scope_down(f_service_); + f_service_ << + endl << + indent() << "G_OBJECT_CLASS (" << class_name_lc << "_parent_class)" + "->dispose (gobject);" << endl; + scope_down(f_service_); + f_service_ << endl; + + // Generate processor finalize function + f_service_ << + "static void" << endl << + class_name_lc << "_finalize (GObject *gobject)" << endl; + scope_up(f_service_); + f_service_ << + indent() << this->nspace << service_name_ << "Processor *self = " << + this->nspace_uc << service_name_uc << "_PROCESSOR (gobject);" << endl << + endl << + indent() << "g_hash_table_destroy (self->process_map);" << endl << + endl << + indent() << "G_OBJECT_CLASS (" << class_name_lc << "_parent_class)" + "->finalize (gobject);" << endl; + scope_down(f_service_); + f_service_ << endl; + + // Generate processor instance initializer + f_service_ << + "static void" << endl << + class_name_lc << "_init (" << class_name << " *self)" << endl; + scope_up(f_service_); + f_service_ << + indent() << "self->handler = NULL;" << endl << + indent() << "self->process_map = " + "g_hash_table_new (g_str_hash, g_str_equal);" << endl << + endl; + args_indent = string(21, ' '); + for (function_iter = functions.begin(); + function_iter != functions.end(); + ++function_iter) { + string service_function_name = (*function_iter)->get_name(); + string process_function_name = + class_name_lc + + "_process_" + + initial_caps_to_underscores(service_function_name); + + f_service_ << + indent() << "g_hash_table_insert (self->process_map," << endl << + indent() + args_indent + "\"" << service_function_name << "\", " << endl << + indent() + args_indent + process_function_name << ");" << endl; + } + scope_down(f_service_); + f_service_ << + endl; + + // Generate processor class initializer + f_service_ << + "static void" << endl << + class_name_lc << "_class_init (" << class_name << "Class *cls)" << endl; + scope_up(f_service_); + f_service_ << + indent() << "GObjectClass *gobject_class = G_OBJECT_CLASS (cls);" << endl << + indent() << "ThriftDispatchProcessorClass *dispatch_processor_class =" << endl; + indent_up(); + f_service_ << + indent() << "THRIFT_DISPATCH_PROCESSOR_CLASS (cls);" << endl; + indent_down(); + f_service_ << + indent() << "GParamSpec *param_spec;" << endl << + endl << + indent() << "gobject_class->dispose = " << + class_name_lc << "_dispose;" << endl << + indent() << "gobject_class->finalize = " << + class_name_lc << "_finalize;" << endl << + indent() << "gobject_class->set_property = " << + class_name_lc << "_set_property;" << endl << + indent() << "gobject_class->get_property = " << + class_name_lc << "_get_property;" << endl << + endl << + indent() << "dispatch_processor_class->dispatch_call = " << + class_name_lc << "_dispatch_call;" << endl << + indent() << "cls->dispatch_call = " << + class_name_lc << "_dispatch_call;" << endl << + endl << + indent() << "param_spec = g_param_spec_object (\"handler\"," << endl; + args_indent = indent() + string(34, ' '); + f_service_ << + args_indent << "\"Service handler implementation\"," << endl << + args_indent << "\"The service handler implementation \"" << endl << + args_indent << "\"to which method calls are dispatched.\"," << endl << + args_indent << this->nspace_uc + "TYPE_" + service_name_uc + "_HANDLER," << endl << + args_indent << "G_PARAM_READWRITE);" << endl; + f_service_ << + indent() << "g_object_class_install_property (gobject_class," << endl; + args_indent = indent() + string (33, ' '); + f_service_ << + args_indent << "PROP_" << class_name_uc << "_HANDLER," << endl << + args_indent << "param_spec);" << endl; + scope_down(f_service_); +} + +/** * Generates C code that represents a Thrift service server. */ void t_c_glib_generator::generate_service_server (t_service *tservice) { (void) tservice; - /* get some C friendly service names */ - string service_name_u = initial_caps_to_underscores(service_name_); - string service_name_uc = to_upper_case(service_name_u); + // Generate the service's handler class + generate_service_handler (tservice); - // write the server object instance definition in the header. - // TODO: implement after implement TServer and TProcessor + // Generate the service's processor class + generate_service_processor (tservice); } /** @@ -2019,7 +3237,7 @@ void t_c_glib_generator::generate_object(t_struct *tstruct) { f_types_impl_ << indent() << "self->" << member_name << " = " << assign_function_name << " (value);" << endl; - } else if (member_type->is_struct()) { + } else if (member_type->is_struct() || member_type->is_xception()) { f_types_impl_ << indent() << "if (self->" << member_name << " != NULL)" << endl; indent_up(); @@ -2120,7 +3338,7 @@ void t_c_glib_generator::generate_object(t_struct *tstruct) { } } else if (member_type->is_enum()) { setter_function_name = "g_value_set_int"; - } else if (member_type->is_struct()) { + } else if (member_type->is_struct() || member_type->is_xception()) { setter_function_name = "g_value_set_object"; } else if (member_type->is_container()) { setter_function_name = "g_value_set_boxed"; @@ -2526,7 +3744,7 @@ void t_c_glib_generator::generate_object(t_struct *tstruct) { args_indent << min_value << "," << endl << args_indent << "G_PARAM_READWRITE));" << endl; indent_down(); - } else if (member_type->is_struct()) { + } else if (member_type->is_struct() || member_type->is_xception()) { string param_type = this->nspace_uc + "TYPE_" + @@ -3772,5 +4990,38 @@ string initial_caps_to_underscores(string name) { return ret; } +/** + * Performs the reverse operation of initial_caps_to_underscores: The first + * character of the string is made uppercase, along with each character that + * follows an underscore (which is removed). Useful for converting Thrift + * service-method names into GObject-style class names. + * + * Input: "zomg_camel_case" + * Output: "ZomgCamelCase" + */ +string underscores_to_initial_caps(string name) { + string ret; + const char *tmp = name.c_str(); + bool uppercase_next = true; + + for (unsigned int i = 0; i < name.length(); i++) { + char c = tmp[i]; + if (c == '_') { + uppercase_next = true; + } + else { + if (uppercase_next) { + ret += toupper (c); + uppercase_next = false; + } + else { + ret += c; + } + } + } + + return ret; +} + /* register this generator with the main program */ THRIFT_REGISTER_GENERATOR(c_glib, "C, using GLib", "") http://git-wip-us.apache.org/repos/asf/thrift/blob/63243c6a/lib/c_glib/Makefile.am ---------------------------------------------------------------------- diff --git a/lib/c_glib/Makefile.am b/lib/c_glib/Makefile.am index 35f1114..39e848a 100755 --- a/lib/c_glib/Makefile.am +++ b/lib/c_glib/Makefile.am @@ -36,12 +36,15 @@ libthrift_c_glib_la_SOURCES = src/thrift/c_glib/thrift.c \ src/thrift/c_glib/thrift_struct.c \ src/thrift/c_glib/thrift_application_exception.c \ src/thrift/c_glib/processor/thrift_processor.c \ + src/thrift/c_glib/processor/thrift_dispatch_processor.c \ src/thrift/c_glib/protocol/thrift_protocol.c \ src/thrift/c_glib/protocol/thrift_protocol_factory.c \ src/thrift/c_glib/protocol/thrift_binary_protocol.c \ src/thrift/c_glib/protocol/thrift_binary_protocol_factory.c \ src/thrift/c_glib/transport/thrift_transport.c \ src/thrift/c_glib/transport/thrift_transport_factory.c \ + src/thrift/c_glib/transport/thrift_buffered_transport_factory.c \ + src/thrift/c_glib/transport/thrift_framed_transport_factory.c \ src/thrift/c_glib/transport/thrift_socket.c \ src/thrift/c_glib/transport/thrift_server_transport.c \ src/thrift/c_glib/transport/thrift_server_socket.c \ @@ -74,14 +77,17 @@ include_transport_HEADERS = src/thrift/c_glib/transport/thrift_buffered_transpor src/thrift/c_glib/transport/thrift_server_transport.h \ src/thrift/c_glib/transport/thrift_socket.h \ src/thrift/c_glib/transport/thrift_transport.h \ - src/thrift/c_glib/transport/thrift_transport_factory.h + src/thrift/c_glib/transport/thrift_transport_factory.h \ + src/thrift/c_glib/transport/thrift_buffered_transport_factory.h \ + src/thrift/c_glib/transport/thrift_framed_transport_factory.h include_serverdir = $(include_thriftdir)/server include_server_HEADERS = src/thrift/c_glib/server/thrift_server.h \ src/thrift/c_glib/server/thrift_simple_server.h include_processordir = $(include_thriftdir)/processor -include_processor_HEADERS = src/thrift/c_glib/processor/thrift_processor.h +include_processor_HEADERS = src/thrift/c_glib/processor/thrift_processor.h \ + src/thrift/c_glib/processor/thrift_dispatch_processor.h EXTRA_DIST = \ http://git-wip-us.apache.org/repos/asf/thrift/blob/63243c6a/lib/c_glib/src/thrift/c_glib/processor/thrift_dispatch_processor.c ---------------------------------------------------------------------- diff --git a/lib/c_glib/src/thrift/c_glib/processor/thrift_dispatch_processor.c b/lib/c_glib/src/thrift/c_glib/processor/thrift_dispatch_processor.c new file mode 100644 index 0000000..7d223bf --- /dev/null +++ b/lib/c_glib/src/thrift/c_glib/processor/thrift_dispatch_processor.c @@ -0,0 +1,142 @@ +/* + * 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. + */ + +#include <thrift/c_glib/thrift.h> +#include <thrift/c_glib/thrift_application_exception.h> +#include <thrift/c_glib/processor/thrift_dispatch_processor.h> + +G_DEFINE_ABSTRACT_TYPE (ThriftDispatchProcessor, + thrift_dispatch_processor, + THRIFT_TYPE_PROCESSOR); + +gboolean +thrift_dispatch_processor_process (ThriftProcessor *processor, + ThriftProtocol *in, + ThriftProtocol *out, + GError **error) +{ + gchar *fname; + ThriftMessageType mtype; + gint32 seqid; + ThriftDispatchProcessor *dispatch_processor = + THRIFT_DISPATCH_PROCESSOR (processor); + + /* Read the start of the message, which we expect to be a method call */ + if (thrift_protocol_read_message_begin (in, + &fname, + &mtype, + &seqid, + error) < 0) { + g_warning ("error reading start of message: %s", + (error != NULL) ? (*error)->message : "(null)"); + return FALSE; + } + else if (mtype != T_CALL && mtype != T_ONEWAY) { + g_warning ("received invalid message type %d from client", mtype); + return FALSE; + } + + /* Dispatch the method call */ + return THRIFT_DISPATCH_PROCESSOR_GET_CLASS (dispatch_processor) + ->dispatch_call (dispatch_processor, + in, + out, + fname, + seqid, + error); +} + +static gboolean +thrift_dispatch_processor_real_dispatch_call (ThriftDispatchProcessor *self, + ThriftProtocol *in, + ThriftProtocol *out, + gchar *fname, + gint32 seqid, + GError **error) +{ + ThriftTransport *transport; + ThriftApplicationException *xception; + gchar *message; + gint32 result; + gboolean dispatch_result = FALSE; + + THRIFT_UNUSED_VAR (self); + + /* By default, return an application exception to the client indicating the + method name is not recognized. */ + + if ((thrift_protocol_skip (in, T_STRUCT, error) < 0) || + (thrift_protocol_read_message_end (in, error) < 0)) + return FALSE; + + g_object_get (in, "transport", &transport, NULL); + result = thrift_transport_read_end (transport, error); + g_object_unref (transport); + if (result < 0) + return FALSE; + + if (thrift_protocol_write_message_begin (out, + fname, + T_EXCEPTION, + seqid, + error) < 0) + return FALSE; + message = g_strconcat ("Invalid method name: '", fname, "'", NULL); + xception = + g_object_new (THRIFT_TYPE_APPLICATION_EXCEPTION, + "type", THRIFT_APPLICATION_EXCEPTION_ERROR_UNKNOWN_METHOD, + "message", message, + NULL); + g_free (message); + result = thrift_struct_write (THRIFT_STRUCT (xception), + out, + error); + g_object_unref (xception); + if ((result < 0) || + (thrift_protocol_write_message_end (out, error) < 0)) + return FALSE; + + g_object_get (out, "transport", &transport, NULL); + dispatch_result = + ((thrift_transport_write_end (transport, error) >= 0) && + (thrift_transport_flush (transport, error) >= 0)); + g_object_unref (transport); + + return dispatch_result; +} + +static void +thrift_dispatch_processor_init (ThriftDispatchProcessor *self) +{ + THRIFT_UNUSED_VAR (self); +} + +static void +thrift_dispatch_processor_class_init (ThriftDispatchProcessorClass *klass) +{ + ThriftProcessorClass *processor_class = + THRIFT_PROCESSOR_CLASS (klass); + + /* Implement ThriftProcessor's process method */ + processor_class->process = thrift_dispatch_processor_process; + + /* Provide a default implement for dispatch_call, which returns an exception + to the client indicating the method name was not recognized */ + klass->dispatch_call = thrift_dispatch_processor_real_dispatch_call; +} http://git-wip-us.apache.org/repos/asf/thrift/blob/63243c6a/lib/c_glib/src/thrift/c_glib/processor/thrift_dispatch_processor.h ---------------------------------------------------------------------- diff --git a/lib/c_glib/src/thrift/c_glib/processor/thrift_dispatch_processor.h b/lib/c_glib/src/thrift/c_glib/processor/thrift_dispatch_processor.h new file mode 100644 index 0000000..5afb85e --- /dev/null +++ b/lib/c_glib/src/thrift/c_glib/processor/thrift_dispatch_processor.h @@ -0,0 +1,95 @@ +/* + * 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. + */ + +#ifndef _THRIFT_DISPATCH_PROCESSOR_H +#define _THRIFT_DISPATCH_PROCESSOR_H + +#include <glib-object.h> + +#include <thrift/c_glib/processor/thrift_processor.h> + +G_BEGIN_DECLS + +/*! \file thrift_dispatch_processor.h + * \brief Parses a method-call message header and invokes a function + * to dispatch the call by function name. + * + * ThriftDispatchProcessor is an abstract helper class that parses the + * header of a method-call message and invokes a member function, + * dispatch_call, with the method's name. + * + * Subclasses must implement dispatch_call to dispatch the method call + * to the implementing function. + */ + +/* Type macros */ +#define THRIFT_TYPE_DISPATCH_PROCESSOR (thrift_dispatch_processor_get_type ()) +#define THRIFT_DISPATCH_PROCESSOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THRIFT_TYPE_DISPATCH_PROCESSOR, ThriftDispatchProcessor)) +#define THRIFT_IS_DISPATCH_PROCESSOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THRIFT_TYPE_DISPATCH_PROCESSOR)) +#define THRIFT_DISPATCH_PROCESSOR_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), THRIFT_TYPE_DISPATCH_PROCESSOR, ThriftDispatchProcessorClass)) +#define THRIFT_IS_DISPATCH_PROCESSOR_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), THRIFT_TYPE_DISPATCH_PROCESSOR)) +#define THRIFT_DISPATCH_PROCESSOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THRIFT_TYPE_DISPATCH_PROCESSOR, ThriftDispatchProcessorClass)) + +/*! + * Thrift Dispatch Processor object + */ +struct _ThriftDispatchProcessor +{ + ThriftProcessor parent; +}; +typedef struct _ThriftDispatchProcessor ThriftDispatchProcessor; + +/*! + * Thrift Dispatch Processor class + */ +struct _ThriftDispatchProcessorClass +{ + ThriftProcessorClass parent; + + /* public */ + gboolean (*process) (ThriftProcessor *processor, + ThriftProtocol *in, + ThriftProtocol *out, + GError **error); + + /* protected */ + gboolean (*dispatch_call) (ThriftDispatchProcessor *self, + ThriftProtocol *in, + ThriftProtocol *out, + gchar *fname, + gint32 seqid, + GError **error); +}; +typedef struct _ThriftDispatchProcessorClass ThriftDispatchProcessorClass; + +/* Used by THRIFT_TYPE_DISPATCH_PROCESSOR */ +GType thrift_dispatch_processor_get_type (void); + +/*! + * Processes a request. + * \public \memberof ThriftDispatchProcessorClass + */ +gboolean thrift_dispatch_processor_process (ThriftProcessor *processor, + ThriftProtocol *in, + ThriftProtocol *out, + GError **error); + +G_END_DECLS + +#endif /* _THRIFT_DISPATCH_PROCESSOR_H */ http://git-wip-us.apache.org/repos/asf/thrift/blob/63243c6a/lib/c_glib/src/thrift/c_glib/processor/thrift_processor.c ---------------------------------------------------------------------- diff --git a/lib/c_glib/src/thrift/c_glib/processor/thrift_processor.c b/lib/c_glib/src/thrift/c_glib/processor/thrift_processor.c index dac8783..c242c25 100644 --- a/lib/c_glib/src/thrift/c_glib/processor/thrift_processor.c +++ b/lib/c_glib/src/thrift/c_glib/processor/thrift_processor.c @@ -24,9 +24,10 @@ G_DEFINE_ABSTRACT_TYPE(ThriftProcessor, thrift_processor, G_TYPE_OBJECT) gboolean thrift_processor_process (ThriftProcessor *processor, ThriftProtocol *in, - ThriftProtocol *out) + ThriftProtocol *out, GError **error) { - return THRIFT_PROCESSOR_GET_CLASS (processor)->process (processor, in, out); + return + THRIFT_PROCESSOR_GET_CLASS (processor)->process (processor, in, out, error); } /* class initializer for ThriftProcessor */ http://git-wip-us.apache.org/repos/asf/thrift/blob/63243c6a/lib/c_glib/src/thrift/c_glib/processor/thrift_processor.h ---------------------------------------------------------------------- diff --git a/lib/c_glib/src/thrift/c_glib/processor/thrift_processor.h b/lib/c_glib/src/thrift/c_glib/processor/thrift_processor.h index a96a555..ff2d2da 100644 --- a/lib/c_glib/src/thrift/c_glib/processor/thrift_processor.h +++ b/lib/c_glib/src/thrift/c_glib/processor/thrift_processor.h @@ -56,7 +56,7 @@ struct _ThriftProcessorClass /* vtable */ gboolean (*process) (ThriftProcessor *processor, ThriftProtocol *in, - ThriftProtocol *out); + ThriftProtocol *out, GError **error); }; typedef struct _ThriftProcessorClass ThriftProcessorClass; @@ -68,7 +68,8 @@ GType thrift_processor_get_type (void); * \public \memberof ThriftProcessorClass */ gboolean thrift_processor_process (ThriftProcessor *processor, - ThriftProtocol *in, ThriftProtocol *out); + ThriftProtocol *in, ThriftProtocol *out, + GError **error); G_END_DECLS http://git-wip-us.apache.org/repos/asf/thrift/blob/63243c6a/lib/c_glib/src/thrift/c_glib/server/thrift_server.c ---------------------------------------------------------------------- diff --git a/lib/c_glib/src/thrift/c_glib/server/thrift_server.c b/lib/c_glib/src/thrift/c_glib/server/thrift_server.c index 0171cee..e8aff45 100644 --- a/lib/c_glib/src/thrift/c_glib/server/thrift_server.c +++ b/lib/c_glib/src/thrift/c_glib/server/thrift_server.c @@ -96,10 +96,10 @@ thrift_server_set_property (GObject *object, guint property_id, } } -void -thrift_server_serve (ThriftServer *server) +gboolean +thrift_server_serve (ThriftServer *server, GError **error) { - THRIFT_SERVER_GET_CLASS (server)->serve (server); + return THRIFT_SERVER_GET_CLASS (server)->serve (server, error); } void http://git-wip-us.apache.org/repos/asf/thrift/blob/63243c6a/lib/c_glib/src/thrift/c_glib/server/thrift_server.h ---------------------------------------------------------------------- diff --git a/lib/c_glib/src/thrift/c_glib/server/thrift_server.h b/lib/c_glib/src/thrift/c_glib/server/thrift_server.h index 2744f97..49beddc 100644 --- a/lib/c_glib/src/thrift/c_glib/server/thrift_server.h +++ b/lib/c_glib/src/thrift/c_glib/server/thrift_server.h @@ -69,7 +69,7 @@ struct _ThriftServerClass GObjectClass parent; /* vtable */ - void (*serve) (ThriftServer *server); + gboolean (*serve) (ThriftServer *server, GError **error); void (*stop) (ThriftServer *server); }; @@ -80,7 +80,7 @@ GType thrift_server_get_type (void); * Processes the request. * \public \memberof ThriftServerClass */ -void thrift_server_serve (ThriftServer *server); +gboolean thrift_server_serve (ThriftServer *server, GError **error); /*! * Stop handling requests. http://git-wip-us.apache.org/repos/asf/thrift/blob/63243c6a/lib/c_glib/src/thrift/c_glib/server/thrift_simple_server.c ---------------------------------------------------------------------- diff --git a/lib/c_glib/src/thrift/c_glib/server/thrift_simple_server.c b/lib/c_glib/src/thrift/c_glib/server/thrift_simple_server.c index 7a39bc2..cb20ab6 100644 --- a/lib/c_glib/src/thrift/c_glib/server/thrift_simple_server.c +++ b/lib/c_glib/src/thrift/c_glib/server/thrift_simple_server.c @@ -24,51 +24,71 @@ G_DEFINE_TYPE(ThriftSimpleServer, thrift_simple_server, THRIFT_TYPE_SERVER) -void -thrift_simple_server_serve (ThriftServer *server) +gboolean +thrift_simple_server_serve (ThriftServer *server, GError **error) { - g_return_if_fail (THRIFT_IS_SIMPLE_SERVER (server)); + g_return_val_if_fail (THRIFT_IS_SIMPLE_SERVER (server), FALSE); ThriftTransport *t = NULL; ThriftTransport *input_transport = NULL, *output_transport = NULL; ThriftProtocol *input_protocol = NULL, *output_protocol = NULL; ThriftSimpleServer *tss = THRIFT_SIMPLE_SERVER(server); + GError *process_error = NULL; - THRIFT_SERVER_TRANSPORT_GET_CLASS (server->server_transport) - ->listen (server->server_transport, NULL); - - tss->running = TRUE; - while (tss->running == TRUE) - { - t = thrift_server_transport_accept (server->server_transport, NULL); - input_transport = - THRIFT_TRANSPORT_FACTORY_GET_CLASS (server->input_transport_factory) - ->get_transport (server->input_transport_factory, t); - output_transport = - THRIFT_TRANSPORT_FACTORY_GET_CLASS (server->output_transport_factory) - ->get_transport (server->output_transport_factory, t); - input_protocol = - THRIFT_PROTOCOL_FACTORY_GET_CLASS (server->input_protocol_factory) - ->get_protocol (server->input_protocol_factory, t); - output_protocol = - THRIFT_PROTOCOL_FACTORY_GET_CLASS (server->output_protocol_factory) - ->get_protocol (server->output_protocol_factory, t); - - while (THRIFT_PROCESSOR_GET_CLASS (server->processor) - ->process (server->processor, input_protocol, output_protocol)) + if (thrift_server_transport_listen (server->server_transport, error)) { + tss->running = TRUE; + while (tss->running == TRUE) { - // TODO: implement transport peek () + t = thrift_server_transport_accept (server->server_transport, + error); + if (t != NULL && tss->running) { + input_transport = + THRIFT_TRANSPORT_FACTORY_GET_CLASS (server->input_transport_factory) + ->get_transport (server->input_transport_factory, t); + output_transport = + THRIFT_TRANSPORT_FACTORY_GET_CLASS (server->output_transport_factory) + ->get_transport (server->output_transport_factory, t); + input_protocol = + THRIFT_PROTOCOL_FACTORY_GET_CLASS (server->input_protocol_factory) + ->get_protocol (server->input_protocol_factory, input_transport); + output_protocol = + THRIFT_PROTOCOL_FACTORY_GET_CLASS (server->output_protocol_factory) + ->get_protocol (server->output_protocol_factory, output_transport); + + while (THRIFT_PROCESSOR_GET_CLASS (server->processor) + ->process (server->processor, + input_protocol, + output_protocol, + &process_error) && + thrift_transport_peek (input_transport, &process_error)) + { + } + + if (process_error != NULL) + { + g_message ("thrift_simple_server_serve: %s", process_error->message); + g_clear_error (&process_error); + + // Note we do not propagate processing errors to the caller as they + // normally are transient and not fatal to the server + } + + // TODO: handle exceptions + THRIFT_TRANSPORT_GET_CLASS (input_transport)->close (input_transport, + NULL); + THRIFT_TRANSPORT_GET_CLASS (output_transport)->close (output_transport, + NULL); + } } - // TODO: handle exceptions - THRIFT_TRANSPORT_GET_CLASS (input_transport)->close (input_transport, NULL); - THRIFT_TRANSPORT_GET_CLASS (output_transport)->close (output_transport, - NULL); - } + // attempt to shutdown + THRIFT_SERVER_TRANSPORT_GET_CLASS (server->server_transport) + ->close (server->server_transport, NULL); + } - // attempt to shutdown - THRIFT_SERVER_TRANSPORT_GET_CLASS (server->server_transport) - ->close (server->server_transport, NULL); + // Since this method is designed to run forever, it can only ever return on + // error + return FALSE; } void http://git-wip-us.apache.org/repos/asf/thrift/blob/63243c6a/lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport.c ---------------------------------------------------------------------- diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport.c b/lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport.c index 76d4fda..ee8e1aa 100644 --- a/lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport.c +++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport.c @@ -47,6 +47,14 @@ thrift_buffered_transport_is_open (ThriftTransport *transport) return THRIFT_TRANSPORT_GET_CLASS (t->transport)->is_open (t->transport); } +/* overrides thrift_transport_peek */ +gboolean +thrift_buffered_transport_peek (ThriftTransport *transport, GError **error) +{ + ThriftBufferedTransport *t = THRIFT_BUFFERED_TRANSPORT (transport); + return (t->r_buf->len > 0) || thrift_transport_peek (t->transport, error); +} + /* implements thrift_transport_open */ gboolean thrift_buffered_transport_open (ThriftTransport *transport, GError **error) @@ -369,6 +377,7 @@ thrift_buffered_transport_class_init (ThriftBufferedTransportClass *cls) gobject_class->finalize = thrift_buffered_transport_finalize; ttc->is_open = thrift_buffered_transport_is_open; + ttc->peek = thrift_buffered_transport_peek; ttc->open = thrift_buffered_transport_open; ttc->close = thrift_buffered_transport_close; ttc->read = thrift_buffered_transport_read; http://git-wip-us.apache.org/repos/asf/thrift/blob/63243c6a/lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport_factory.c ---------------------------------------------------------------------- diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport_factory.c b/lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport_factory.c new file mode 100644 index 0000000..86050b6 --- /dev/null +++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport_factory.c @@ -0,0 +1,55 @@ +/* + * 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. + */ + +#include <thrift/c_glib/thrift.h> +#include <thrift/c_glib/transport/thrift_buffered_transport.h> +#include <thrift/c_glib/transport/thrift_buffered_transport_factory.h> + +G_DEFINE_TYPE (ThriftBufferedTransportFactory, + thrift_buffered_transport_factory, + THRIFT_TYPE_TRANSPORT_FACTORY) + +/* Wraps a transport with a ThriftBufferedTransport. */ +ThriftTransport * +thrift_buffered_transport_factory_get_transport (ThriftTransportFactory *factory, + ThriftTransport *transport) +{ + THRIFT_UNUSED_VAR (factory); + + return THRIFT_TRANSPORT (g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT, + "transport", transport, + NULL)); +} + +static void +thrift_buffered_transport_factory_init (ThriftBufferedTransportFactory *self) +{ + THRIFT_UNUSED_VAR (self); +} + +static void +thrift_buffered_transport_factory_class_init (ThriftBufferedTransportFactoryClass *klass) +{ + ThriftTransportFactoryClass *base_class = + THRIFT_TRANSPORT_FACTORY_CLASS (klass); + + base_class->get_transport = + klass->get_transport = + thrift_buffered_transport_factory_get_transport; +} http://git-wip-us.apache.org/repos/asf/thrift/blob/63243c6a/lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport_factory.h ---------------------------------------------------------------------- diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport_factory.h b/lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport_factory.h new file mode 100644 index 0000000..d43f4e4 --- /dev/null +++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_buffered_transport_factory.h @@ -0,0 +1,86 @@ +/* + * 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. + */ + +#ifndef _THRIFT_BUFFERED_TRANSPORT_FACTORY_H +#define _THRIFT_BUFFERED_TRANSPORT_FACTORY_H + +#include <glib-object.h> + +#include <thrift/c_glib/transport/thrift_transport.h> +#include <thrift/c_glib/transport/thrift_transport_factory.h> + +G_BEGIN_DECLS + +/*! \file thrift_buffered_transport_factory.h + * \brief Wraps a transport with a ThriftBufferedTransport. + */ + +/* type macros */ +#define THRIFT_TYPE_BUFFERED_TRANSPORT_FACTORY \ + (thrift_buffered_transport_factory_get_type ()) +#define THRIFT_BUFFERED_TRANSPORT_FACTORY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + THRIFT_TYPE_BUFFERED_TRANSPORT_FACTORY, \ + ThriftBufferedTransportFactory)) +#define THRIFT_IS_BUFFERED_TRANSPORT_FACTORY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + THRIFT_TYPE_BUFFERED_TRANSPORT_FACTORY)) +#define THRIFT_BUFFERED_TRANSPORT_FACTORY_CLASS(c) \ + (G_TYPE_CHECK_CLASS_CAST ((c), \ + THRIFT_TYPE_BUFFERED_TRANSPORT_FACTORY, \ + ThriftBufferedTransportFactoryClass)) +#define THRIFT_IS_BUFFERED_TRANSPORT_FACTORY_CLASS(c) \ + (G_TYPE_CHECK_CLASS_TYPE ((c), \ + THRIFT_TYPE_BUFFERED_TRANSPORT_FACTORY)) +#define THRIFT_BUFFERED_TRANSPORT_FACTORY_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + THRIFT_TYPE_BUFFERED_TRANSPORT_FACTORY, \ + ThriftBufferedTransportFactoryClass)) + +typedef struct _ThriftBufferedTransportFactory ThriftBufferedTransportFactory; + +/* Thrift Buffered-Transport Factory instance */ +struct _ThriftBufferedTransportFactory +{ + ThriftTransportFactory parent; +}; + +typedef struct _ThriftBufferedTransportFactoryClass ThriftBufferedTransportFactoryClass; + +/* Thrift Buffered-Transport Factory class */ +struct _ThriftBufferedTransportFactoryClass +{ + ThriftTransportFactoryClass parent; + + /* vtable */ + ThriftTransport *(*get_transport) (ThriftTransportFactory *factory, + ThriftTransport *transport); +}; + +/* used by THRIFT_TYPE_BUFFERED_TRANSPORT_FACTORY */ +GType thrift_buffered_transport_factory_get_type (void); + +/* virtual public methods */ +ThriftTransport * +thrift_buffered_transport_factory_get_transport (ThriftTransportFactory *factory, + ThriftTransport *transport); + +G_END_DECLS + +#endif /* _THRIFT_BUFFERED_TRANSPORT_FACTORY_H */ http://git-wip-us.apache.org/repos/asf/thrift/blob/63243c6a/lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport.c ---------------------------------------------------------------------- diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport.c b/lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport.c index 9810aa6..47a7960 100644 --- a/lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport.c +++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport.c @@ -49,6 +49,14 @@ thrift_framed_transport_is_open (ThriftTransport *transport) return THRIFT_TRANSPORT_GET_CLASS (t->transport)->is_open (t->transport); } +/* overrides thrift_transport_peek */ +gboolean +thrift_framed_transport_peek (ThriftTransport *transport, GError **error) +{ + ThriftFramedTransport *t = THRIFT_FRAMED_TRANSPORT (transport); + return (t->r_buf->len > 0) || thrift_transport_peek (t->transport, error); +} + /* implements thrift_transport_open */ gboolean thrift_framed_transport_open (ThriftTransport *transport, GError **error) @@ -361,6 +369,7 @@ thrift_framed_transport_class_init (ThriftFramedTransportClass *cls) gobject_class->finalize = thrift_framed_transport_finalize; ttc->is_open = thrift_framed_transport_is_open; + ttc->peek = thrift_framed_transport_peek; ttc->open = thrift_framed_transport_open; ttc->close = thrift_framed_transport_close; ttc->read = thrift_framed_transport_read; http://git-wip-us.apache.org/repos/asf/thrift/blob/63243c6a/lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport_factory.c ---------------------------------------------------------------------- diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport_factory.c b/lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport_factory.c new file mode 100644 index 0000000..e68fe0a --- /dev/null +++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_framed_transport_factory.c @@ -0,0 +1,55 @@ +/* + * 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. + */ + +#include <thrift/c_glib/thrift.h> +#include <thrift/c_glib/transport/thrift_framed_transport.h> +#include <thrift/c_glib/transport/thrift_framed_transport_factory.h> + +G_DEFINE_TYPE (ThriftFramedTransportFactory, + thrift_framed_transport_factory, + THRIFT_TYPE_TRANSPORT_FACTORY) + +/* Wraps a transport with a ThriftFramedTransport. */ +ThriftTransport * +thrift_framed_transport_factory_get_transport (ThriftTransportFactory *factory, + ThriftTransport *transport) +{ + THRIFT_UNUSED_VAR (factory); + + return THRIFT_TRANSPORT (g_object_new (THRIFT_TYPE_FRAMED_TRANSPORT, + "transport", transport, + NULL)); +} + +static void +thrift_framed_transport_factory_init (ThriftFramedTransportFactory *self) +{ + THRIFT_UNUSED_VAR (self); +} + +static void +thrift_framed_transport_factory_class_init (ThriftFramedTransportFactoryClass *klass) +{ + ThriftTransportFactoryClass *base_class = + THRIFT_TRANSPORT_FACTORY_CLASS (klass); + + base_class->get_transport = + klass->get_transport = + thrift_framed_transport_factory_get_transport; +}
