void t_c_glib_generator::generate_service_processor()

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_);
}