in compiler/cpp/src/thrift/generate/t_c_glib_generator.cc [2059:2778]
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 service_processor_name = service_name_ + "Processor";
string class_name = this->nspace + service_processor_name;
string class_name_lc = this->nspace_lc + initial_caps_to_underscores(service_processor_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 process_function_type_name = class_name + "ProcessFunction";
string process_function_def_type_name =
class_name_lc + "_process_function_def";
string function_name;
string args_indent;
// The service this service extends, or nullptr 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 */" << '\n' << "struct _" << class_name << '\n'
<< "{" << '\n';
indent_up();
f_header_ << indent() << parent_class_name << " parent;" << '\n' << '\n' << indent()
<< "/* protected */" << '\n' << indent()
<< this->nspace + service_name_ + "Handler *handler;" << '\n' << indent()
<< "GHashTable *process_map;" << '\n';
indent_down();
f_header_ << "};" << '\n' << "typedef struct _" << class_name << " " << class_name << ";" << '\n'
<< '\n';
// Generate the processor class definition
f_header_ << "struct _" << class_name << "Class" << '\n' << "{" << '\n';
indent_up();
f_header_ << indent() << parent_class_name << "Class parent;" << '\n' << '\n' << indent()
<< "/* protected */" << '\n' << indent()
<< "gboolean (*dispatch_call) (ThriftDispatchProcessor *processor," << '\n';
args_indent = indent() + string(27, ' ');
f_header_ << args_indent << "ThriftProtocol *in," << '\n' << args_indent << "ThriftProtocol *out,"
<< '\n' << args_indent << "gchar *fname," << '\n' << args_indent << "gint32 seqid,"
<< '\n' << args_indent << "GError **error);" << '\n';
indent_down();
f_header_ << "};" << '\n' << "typedef struct _" << class_name << "Class " << class_name
<< "Class;" << '\n' << '\n';
// Generate the remaining header boilerplate
f_header_ << "GType " << class_name_lc << "_get_type (void);" << '\n' << "#define "
<< this->nspace_uc << "TYPE_" << service_name_uc << "_PROCESSOR "
<< "(" << class_name_lc << "_get_type())" << '\n' << "#define " << class_name_uc
<< "(obj) "
<< "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_"
<< service_name_uc << "_PROCESSOR, " << class_name << "))" << '\n' << "#define "
<< this->nspace_uc << "IS_" << service_name_uc << "_PROCESSOR(obj) "
<< "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc << "TYPE_"
<< service_name_uc << "_PROCESSOR))" << '\n' << "#define " << class_name_uc
<< "_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc << "TYPE_"
<< service_name_uc << "_PROCESSOR, " << class_name << "Class))" << '\n' << "#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))" << '\n' << "#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))" << '\n' << '\n';
// Generate the processor's implementation in the implementation file
// Generate the processor's properties enum
f_service_ << "enum _" << class_name << "Properties" << '\n' << "{" << '\n';
indent_up();
f_service_ << indent() << "PROP_" << class_name_uc << "_0," << '\n' << indent() << "PROP_"
<< class_name_uc << "_HANDLER" << '\n';
indent_down();
f_service_ << "};" << '\n' << '\n';
// Generate the implementation boilerplate
args_indent = string(15, ' ');
f_service_ << "G_DEFINE_TYPE (" << class_name << "," << '\n' << args_indent << class_name_lc
<< "," << '\n' << args_indent << parent_type_name << ")" << '\n' << '\n';
// Generate the processor's processing-function type
args_indent = string(process_function_type_name.length() + 23, ' ');
f_service_ << "typedef gboolean (* " << process_function_type_name << ") ("
<< class_name << " *, " << '\n'
<< args_indent << "gint32," << '\n'
<< args_indent << "ThriftProtocol *," << '\n'
<< args_indent << "ThriftProtocol *," << '\n'
<< args_indent << "GError **);" << '\n'
<< '\n';
// Generate the processor's processing-function-definition type
f_service_ << "typedef struct" << '\n'
<< "{" << '\n';
indent_up();
f_service_ << indent() << "gchar *name;" << '\n'
<< indent() << process_function_type_name << " function;" << '\n';
indent_down();
f_service_ << "} " << process_function_def_type_name << ";" << '\n'
<< '\n';
// Generate forward declarations of the processor's processing functions so we
// can refer to them in the processing-function-definition struct below and
// keep all of the processor's declarations in one place
for (function_iter = functions.begin();
function_iter != functions.end();
++function_iter) {
function_name = class_name_lc + "_process_"
+ initial_caps_to_underscores((*function_iter)->get_name());
args_indent = string(function_name.length() + 2, ' ');
f_service_ << "static gboolean" << '\n'
<< function_name << " ("
<< class_name << " *," << '\n'
<< args_indent << "gint32," << '\n'
<< args_indent << "ThriftProtocol *," << '\n'
<< args_indent << "ThriftProtocol *," << '\n'
<< args_indent << "GError **);" << '\n';
}
f_service_ << '\n';
// Generate the processor's processing-function definitions, if the service
// defines any methods
if (functions.size() > 0) {
f_service_ << indent() << "static " << process_function_def_type_name
<< '\n'
<< indent() << class_name_lc << "_process_function_defs["
<< functions.size() << "] = {" << '\n';
indent_up();
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() << "{" << '\n';
indent_up();
f_service_ << indent() << "\"" << service_function_name << "\"," << '\n'
<< indent() << process_function_name << '\n';
indent_down();
f_service_ << indent() << "}"
<< (function_iter == --functions.end() ? "" : ",") << '\n';
}
indent_down();
f_service_ << indent() << "};" << '\n'
<< '\n';
}
// 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" << '\n' << function_name << " (" << class_name << " *self,"
<< '\n' << args_indent << "gint32 sequence_id," << '\n' << args_indent
<< "ThriftProtocol *input_protocol," << '\n' << args_indent
<< "ThriftProtocol *output_protocol," << '\n' << args_indent << "GError **error)"
<< '\n';
scope_up(f_service_);
f_service_ << indent() << "gboolean result = TRUE;" << '\n'
<< indent() << "ThriftTransport * transport;" << '\n'
<< indent() << "ThriftApplicationException *xception;" << '\n'
<< indent() << args_class_name + " * args =" << '\n';
indent_up();
f_service_ << indent() << "g_object_new (" << args_class_type << ", NULL);" << '\n' << '\n';
indent_down();
if ((*function_iter)->is_oneway()) {
f_service_ << indent() << "THRIFT_UNUSED_VAR (sequence_id);" << '\n' << indent()
<< "THRIFT_UNUSED_VAR (output_protocol);" << '\n' << '\n';
}
f_service_ << indent() << "g_object_get (input_protocol, \"transport\", "
<< "&transport, NULL);" << '\n' << '\n';
// Read the method's arguments from the caller
f_service_ << indent() << "if ((thrift_struct_read (THRIFT_STRUCT (args), "
<< "input_protocol, error) != -1) &&" << '\n' << indent()
<< " (thrift_protocol_read_message_end (input_protocol, "
<< "error) != -1) &&" << '\n' << indent()
<< " (thrift_transport_read_end (transport, error) != FALSE))" << '\n';
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() << ";" << '\n';
}
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;" << '\n';
}
if (has_return_value) {
f_service_ << indent() << property_type_name(return_type) << " return_value;" << '\n';
}
if (!(*function_iter)->is_oneway()) {
f_service_ << indent() << result_class_name << " * result_struct;" << '\n';
}
f_service_ << '\n';
if (args.size() > 0) {
f_service_ << indent() << "g_object_get (args," << '\n';
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 << "," << '\n';
}
f_service_ << args_indent << "NULL);" << '\n' << '\n';
}
if (!(*function_iter)->is_oneway()) {
f_service_ << indent() << "g_object_unref (transport);" << '\n' << indent()
<< "g_object_get (output_protocol, \"transport\", "
<< "&transport, NULL);" << '\n' << '\n' << indent()
<< "result_struct = g_object_new (" << result_class_type << ", NULL);" << '\n';
if (has_return_value) {
f_service_ << indent() << "g_object_get (result_struct, "
"\"success\", &return_value, NULL);" << '\n';
}
f_service_ << '\n';
}
// 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)," << '\n';
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," << '\n';
}
for (arg_iter = args.begin(); arg_iter != args.end(); ++arg_iter) {
f_service_ << args_indent << (*arg_iter)->get_name() << "," << '\n';
}
for (xception_iter = xceptions.begin(); xception_iter != xceptions.end(); ++xception_iter) {
f_service_ << args_indent << "&" << initial_caps_to_underscores((*xception_iter)->get_name())
<< "," << '\n';
}
f_service_ << args_indent << "error) == TRUE)" << '\n';
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\", ";
if (type_name(return_type) != property_type_name(return_type)) {
// Roundtrip cast to fix the position of sign bit.
f_service_ << "(" << property_type_name(return_type) << ")"
<< "(" << type_name(return_type) << ")";
}
f_service_ << "return_value, "
<< "NULL);" << '\n';
f_service_ << '\n';
}
f_service_ << indent() << "result =" << '\n';
indent_up();
f_service_ << indent() << "((thrift_protocol_write_message_begin (output_protocol," << '\n';
args_indent = indent() + string(39, ' ');
f_service_ << args_indent << "\"" << service_function_name << "\"," << '\n' << args_indent
<< "T_REPLY," << '\n' << args_indent << "sequence_id," << '\n' << args_indent
<< "error) != -1) &&" << '\n' << indent()
<< " (thrift_struct_write (THRIFT_STRUCT (result_struct)," << '\n';
args_indent = indent() + string(23, ' ');
f_service_ << args_indent << "output_protocol," << '\n' << args_indent << "error) != -1));"
<< '\n';
indent_down();
}
scope_down(f_service_);
f_service_ << indent() << "else" << '\n';
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)" << '\n';
scope_up(f_service_);
f_service_ << indent() << "g_object_set (result_struct," << '\n';
args_indent = indent() + string(14, ' ');
f_service_ << args_indent << "\"" << (*xception_iter)->get_name() << "\", "
<< (*xception_iter)->get_name() << "," << '\n' << args_indent << "NULL);" << '\n'
<< '\n';
f_service_ << indent() << "g_object_unref ("<< (*xception_iter)->get_name() <<");"<< '\n';
f_service_ << indent() << "result =" << '\n';
indent_up();
f_service_ << indent() << "((thrift_protocol_write_message_begin (output_protocol," << '\n';
args_indent = indent() + string(39, ' ');
f_service_ << args_indent << "\"" << service_function_name << "\"," << '\n' << args_indent
<< "T_REPLY," << '\n' << args_indent << "sequence_id," << '\n' << args_indent
<< "error) != -1) &&" << '\n' << indent()
<< " (thrift_struct_write (THRIFT_STRUCT (result_struct)," << '\n';
args_indent = indent() + string(23, ' ');
f_service_ << args_indent << "output_protocol," << '\n' << args_indent << "error) != -1));"
<< '\n';
indent_down();
scope_down(f_service_);
f_service_ << indent() << "else" << '\n';
}
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)" << '\n';
indent_up();
f_service_ << indent() << "g_warning (\"" << service_name_ << "."
<< (*function_iter)->get_name() << " implementation returned FALSE \"" << '\n'
<< indent() << string(11, ' ') << "\"but did not set an error\");" << '\n' << '\n';
indent_down();
f_service_ << indent() << "xception =" << '\n';
indent_up();
f_service_ << indent() << "g_object_new (THRIFT_TYPE_APPLICATION_EXCEPTION," << '\n';
args_indent = indent() + string(14, ' ');
f_service_ << args_indent << "\"type\", *error != NULL ? (*error)->code :" << '\n'
<< args_indent << string(11, ' ') << "THRIFT_APPLICATION_EXCEPTION_ERROR_UNKNOWN,"
<< '\n' << args_indent << "\"message\", *error != NULL ? (*error)->message : NULL,"
<< '\n' << args_indent << "NULL);" << '\n';
indent_down();
f_service_ << indent() << "g_clear_error (error);" << '\n' << '\n' << indent()
<< "result =" << '\n';
indent_up();
f_service_ << indent() << "((thrift_protocol_write_message_begin (output_protocol," << '\n';
args_indent = indent() + string(39, ' ');
f_service_ << args_indent << "\"" << service_function_name << "\"," << '\n' << args_indent
<< "T_EXCEPTION," << '\n' << args_indent << "sequence_id," << '\n' << args_indent
<< "error) != -1) &&" << '\n' << indent()
<< " (thrift_struct_write (THRIFT_STRUCT (xception)," << '\n';
args_indent = indent() + string(23, ' ');
f_service_ << args_indent << "output_protocol," << '\n' << args_indent << "error) != -1));"
<< '\n';
indent_down();
f_service_ << '\n' << indent() << "g_object_unref (xception);" << '\n';
if (xceptions.size() > 0) {
scope_down(f_service_);
}
scope_down(f_service_);
f_service_ << '\n';
// 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)" << '\n';
indent_up();
if (base_type->is_binary()) {
f_service_ << indent() << "g_byte_array_unref (" << arg_name << ");" << '\n';
} else {
f_service_ << indent() << "g_free (" << arg_name << ");" << '\n';
}
indent_down();
}
} else if (arg_type->is_container()) {
f_service_ << indent() << "if (" << arg_name << " != NULL)" << '\n';
indent_up();
if (arg_type->is_list()) {
t_type* elem_type = ((t_list*)arg_type)->get_elem_type();
f_service_ << indent();
if (is_numeric(elem_type)) {
f_service_ << "g_array_unref";
} else {
f_service_ << "g_ptr_array_unref";
}
f_service_ << " (" << arg_name << ");" << '\n';
} else if (arg_type->is_map() || arg_type->is_set()) {
f_service_ << indent() << "g_hash_table_unref (" << arg_name << ");" << '\n';
}
indent_down();
} else if (arg_type->is_struct()) {
f_service_ << indent() << "if (" << arg_name << " != NULL)" << '\n';
indent_up();
f_service_ << indent() << "g_object_unref (" << arg_name << ");" << '\n';
indent_down();
}
}
if (!(*function_iter)->is_oneway()) {
if (has_return_value) {
// 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)" << '\n';
indent_up();
if (base_type->is_binary()) {
f_service_ << indent() << "g_byte_array_unref (return_value);" << '\n';
} else {
f_service_ << indent() << "g_free (return_value);" << '\n';
}
indent_down();
}
} else if (return_type->is_container()) {
f_service_ << indent() << "if (return_value != NULL)" << '\n';
indent_up();
if (return_type->is_list()) {
t_type* elem_type = ((t_list*)return_type)->get_elem_type();
f_service_ << indent();
if (is_numeric(elem_type)) {
f_service_ << "g_array_unref";
} else {
f_service_ << "g_ptr_array_unref";
}
f_service_ << " (return_value);" << '\n';
} else if (return_type->is_map() || return_type->is_set()) {
f_service_ << indent() << "g_hash_table_unref (return_value);" << '\n';
}
indent_down();
} else if (return_type->is_struct()) {
f_service_ << indent() << "if (return_value != NULL)" << '\n';
indent_up();
f_service_ << indent() << "g_object_unref (return_value);" << '\n';
indent_down();
}
}
f_service_ << indent() << "g_object_unref (result_struct);" << '\n' << '\n' << indent()
<< "if (result == TRUE)" << '\n';
indent_up();
f_service_ << indent() << "result =" << '\n';
indent_up();
f_service_ << indent() << "((thrift_protocol_write_message_end "
<< "(output_protocol, error) != -1) &&" << '\n' << indent()
<< " (thrift_transport_write_end (transport, error) "
<< "!= FALSE) &&" << '\n' << indent()
<< " (thrift_transport_flush (transport, error) "
<< "!= FALSE));" << '\n';
indent_down();
indent_down();
}
scope_down(f_service_);
f_service_ << indent() << "else" << '\n';
indent_up();
f_service_ << indent() << "result = FALSE;" << '\n';
indent_down();
f_service_ << '\n' << indent() << "g_object_unref (transport);" << '\n' << indent()
<< "g_object_unref (args);" << '\n' << '\n' << indent() << "return result;" << '\n';
scope_down(f_service_);
f_service_ << '\n';
}
// 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" << '\n' << function_name
<< " (ThriftDispatchProcessor *dispatch_processor," << '\n' << args_indent
<< "ThriftProtocol *input_protocol," << '\n' << args_indent
<< "ThriftProtocol *output_protocol," << '\n' << args_indent << "gchar *method_name,"
<< '\n' << args_indent << "gint32 sequence_id," << '\n' << args_indent
<< "GError **error)" << '\n';
scope_up(f_service_);
f_service_ << indent() << class_name_lc << "_process_function_def *"
<< "process_function_def;" << '\n';
f_service_ << indent() << "gboolean dispatch_result = FALSE;" << '\n' << '\n' << indent()
<< class_name << " *self = " << class_name_uc << " (dispatch_processor);" << '\n';
f_service_ << indent() << parent_class_name << "Class "
"*parent_class =" << '\n';
indent_up();
f_service_ << indent() << "g_type_class_peek_parent (" << class_name_uc << "_GET_CLASS (self));"
<< '\n';
indent_down();
f_service_ << '\n'
<< indent() << "process_function_def = "
<< "g_hash_table_lookup (self->process_map, method_name);" << '\n'
<< indent() << "if (process_function_def != NULL)" << '\n';
scope_up(f_service_);
args_indent = indent() + string(53, ' ');
f_service_ << indent() << "g_free (method_name);" << '\n'
<< indent() << "dispatch_result = "
<< "(*process_function_def->function) (self," << '\n'
<< args_indent << "sequence_id," << '\n'
<< args_indent << "input_protocol," << '\n'
<< args_indent << "output_protocol," << '\n'
<< args_indent << "error);" << '\n';
scope_down(f_service_);
f_service_ << indent() << "else" << '\n';
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," << '\n';
args_indent = indent() + string(47, ' ');
f_service_ << args_indent << "input_protocol," << '\n' << args_indent << "output_protocol,"
<< '\n' << args_indent << "method_name," << '\n' << args_indent << "sequence_id,"
<< '\n' << args_indent << "error);" << '\n';
scope_down(f_service_);
f_service_ << '\n' << indent() << "return dispatch_result;" << '\n';
scope_down(f_service_);
f_service_ << '\n';
// Generate the processor's property setter
function_name = class_name_lc + "_set_property";
args_indent = string(function_name.length() + 2, ' ');
f_service_ << "static void" << '\n' << function_name << " (GObject *object," << '\n'
<< args_indent << "guint property_id," << '\n' << args_indent << "const GValue *value,"
<< '\n' << args_indent << "GParamSpec *pspec)" << '\n';
scope_up(f_service_);
f_service_ << indent() << class_name << " *self = " << class_name_uc << " (object);" << '\n'
<< '\n' << indent() << "switch (property_id)" << '\n';
scope_up(f_service_);
f_service_ << indent() << "case PROP_" << class_name_uc << "_HANDLER:" << '\n';
indent_up();
f_service_ << indent() << "if (self->handler != NULL)" << '\n';
indent_up();
f_service_ << indent() << "g_object_unref (self->handler);" << '\n';
indent_down();
f_service_ << indent() << "self->handler = g_value_get_object (value);" << '\n' << indent()
<< "g_object_ref (self->handler);" << '\n';
if (extends_service) {
// Chain up to set the handler in every superclass as well
f_service_ << '\n' << indent() << "G_OBJECT_CLASS (" << class_name_lc << "_parent_class)->"
<< '\n';
indent_up();
f_service_ << indent() << "set_property (object, property_id, value, pspec);" << '\n';
indent_down();
}
f_service_ << indent() << "break;" << '\n';
indent_down();
f_service_ << indent() << "default:" << '\n';
indent_up();
f_service_ << indent() << "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);"
<< '\n' << indent() << "break;" << '\n';
indent_down();
scope_down(f_service_);
scope_down(f_service_);
f_service_ << '\n';
// Generate processor's property getter
function_name = class_name_lc + "_get_property";
args_indent = string(function_name.length() + 2, ' ');
f_service_ << "static void" << '\n' << function_name << " (GObject *object," << '\n'
<< args_indent << "guint property_id," << '\n' << args_indent << "GValue *value,"
<< '\n' << args_indent << "GParamSpec *pspec)" << '\n';
scope_up(f_service_);
f_service_ << indent() << class_name << " *self = " << class_name_uc << " (object);" << '\n'
<< '\n' << indent() << "switch (property_id)" << '\n';
scope_up(f_service_);
f_service_ << indent() << "case PROP_" << class_name_uc << "_HANDLER:" << '\n';
indent_up();
f_service_ << indent() << "g_value_set_object (value, self->handler);" << '\n' << indent()
<< "break;" << '\n';
indent_down();
f_service_ << indent() << "default:" << '\n';
indent_up();
f_service_ << indent() << "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);"
<< '\n' << indent() << "break;" << '\n';
indent_down();
scope_down(f_service_);
scope_down(f_service_);
f_service_ << '\n';
// Generator the processor's dispose function
f_service_ << "static void" << '\n' << class_name_lc << "_dispose (GObject *gobject)" << '\n';
scope_up(f_service_);
f_service_ << indent() << class_name << " *self = " << class_name_uc << " (gobject);" << '\n'
<< '\n' << indent() << "if (self->handler != NULL)" << '\n';
scope_up(f_service_);
f_service_ << indent() << "g_object_unref (self->handler);" << '\n' << indent()
<< "self->handler = NULL;" << '\n';
scope_down(f_service_);
f_service_ << '\n' << indent() << "G_OBJECT_CLASS (" << class_name_lc << "_parent_class)"
"->dispose (gobject);"
<< '\n';
scope_down(f_service_);
f_service_ << '\n';
// Generate processor finalize function
f_service_ << "static void" << '\n' << class_name_lc << "_finalize (GObject *gobject)" << '\n';
scope_up(f_service_);
f_service_ << indent() << this->nspace << service_name_ << "Processor *self = " << this->nspace_uc
<< service_name_uc << "_PROCESSOR (gobject);" << '\n' << '\n' << indent()
<< "thrift_safe_hash_table_destroy (self->process_map);" << '\n' << '\n' << indent()
<< "G_OBJECT_CLASS (" << class_name_lc << "_parent_class)"
"->finalize (gobject);" << '\n';
scope_down(f_service_);
f_service_ << '\n';
// Generate processor instance initializer
f_service_ << "static void" << '\n' << class_name_lc << "_init (" << class_name << " *self)"
<< '\n';
scope_up(f_service_);
if (functions.size() > 0) {
f_service_ << indent() << "guint index;" << '\n'
<< '\n';
}
f_service_ << indent() << "self->handler = NULL;" << '\n' << indent()
<< "self->process_map = "
"g_hash_table_new (g_str_hash, g_str_equal);" << '\n';
if (functions.size() > 0) {
args_indent = string(21, ' ');
f_service_ << '\n'
<< indent() << "for (index = 0; index < "
<< functions.size() << "; index += 1)" << '\n';
indent_up();
f_service_ << indent() << "g_hash_table_insert (self->process_map," << '\n'
<< indent() << args_indent
<< class_name_lc << "_process_function_defs[index].name," << '\n'
<< indent() << args_indent
<< "&" << class_name_lc << "_process_function_defs[index]" << ");"
<< '\n';
indent_down();
}
scope_down(f_service_);
f_service_ << '\n';
// Generate processor class initializer
f_service_ << "static void" << '\n' << class_name_lc << "_class_init (" << class_name
<< "Class *cls)" << '\n';
scope_up(f_service_);
f_service_ << indent() << "GObjectClass *gobject_class = G_OBJECT_CLASS (cls);" << '\n'
<< indent() << "ThriftDispatchProcessorClass *dispatch_processor_class =" << '\n';
indent_up();
f_service_ << indent() << "THRIFT_DISPATCH_PROCESSOR_CLASS (cls);" << '\n';
indent_down();
f_service_ << indent() << "GParamSpec *param_spec;" << '\n' << '\n' << indent()
<< "gobject_class->dispose = " << class_name_lc << "_dispose;" << '\n' << indent()
<< "gobject_class->finalize = " << class_name_lc << "_finalize;" << '\n' << indent()
<< "gobject_class->set_property = " << class_name_lc << "_set_property;" << '\n'
<< indent() << "gobject_class->get_property = " << class_name_lc << "_get_property;"
<< '\n' << '\n' << indent()
<< "dispatch_processor_class->dispatch_call = " << class_name_lc << "_dispatch_call;"
<< '\n' << indent() << "cls->dispatch_call = " << class_name_lc << "_dispatch_call;"
<< '\n' << '\n' << indent() << "param_spec = g_param_spec_object (\"handler\","
<< '\n';
args_indent = indent() + string(34, ' ');
f_service_ << args_indent << "\"Service handler implementation\"," << '\n' << args_indent
<< "\"The service handler implementation \"" << '\n' << args_indent
<< "\"to which method calls are dispatched.\"," << '\n' << args_indent
<< this->nspace_uc + "TYPE_" + service_name_uc + "_HANDLER," << '\n' << args_indent
<< "G_PARAM_READWRITE);" << '\n';
f_service_ << indent() << "g_object_class_install_property (gobject_class," << '\n';
args_indent = indent() + string(33, ' ');
f_service_ << args_indent << "PROP_" << class_name_uc << "_HANDLER," << '\n' << args_indent
<< "param_spec);" << '\n';
scope_down(f_service_);
}