void t_delphi_generator::generate_service_client()

in compiler/cpp/src/thrift/generate/t_delphi_generator.cc [1953:2236]


void t_delphi_generator::generate_service_client(t_service* tservice) {
  indent_up();
  string extends = "";
  string extends_client = "TInterfacedObject";
  string implements = async_ ? "Iface, IAsync" : "Iface";

  generate_delphi_doc(s_service, tservice);
  if (tservice->get_extends() != nullptr) {
    extends = type_name(tservice->get_extends(), true, true);
    extends_client = extends + ".TClient";
  }
  indent(s_service) << "TClient = class( " << extends_client << ", " << implements << ")" << '\n';

  indent(s_service) << "public" << '\n';
  indent_up();

  indent(s_service) << "constructor Create( prot: IProtocol); overload;" << '\n';

  indent_impl(s_service_impl) << "constructor " << normalize_clsnm(service_name_, "T")
                              << ".TClient.Create( prot: IProtocol);" << '\n';
  indent_impl(s_service_impl) << "begin" << '\n';
  indent_up_impl();
  indent_impl(s_service_impl) << "Create( prot, prot );" << '\n';
  indent_down_impl();
  indent_impl(s_service_impl) << "end;" << '\n' << '\n';

  indent(s_service)
      << "constructor Create( const iprot: IProtocol; const oprot: IProtocol); overload;" << '\n';

  indent_impl(s_service_impl) << "constructor " << normalize_clsnm(service_name_, "T")
                              << ".TClient.Create( const iprot: IProtocol; const oprot: IProtocol);"
                              << '\n';
  indent_impl(s_service_impl) << "begin" << '\n';
  indent_up_impl();
  indent_impl(s_service_impl) << "inherited Create;" << '\n';
  indent_impl(s_service_impl) << "iprot_ := iprot;" << '\n';
  indent_impl(s_service_impl) << "oprot_ := oprot;" << '\n';
  indent_down_impl();
  indent_impl(s_service_impl) << "end;" << '\n' << '\n';

  indent_down();

  if (extends.empty()) {
    indent(s_service) << "protected" << '\n';
    indent_up();
    indent(s_service) << "iprot_: IProtocol;" << '\n';
    indent(s_service) << "oprot_: IProtocol;" << '\n';
    indent(s_service) << "seqid_: System.Integer;" << '\n';
    indent_down();

    indent(s_service) << "public" << '\n';
    indent_up();
    indent(s_service) << "property InputProtocol: IProtocol read iprot_;" << '\n';
    indent(s_service) << "property OutputProtocol: IProtocol read oprot_;" << '\n';
    indent_down();
  }

  vector<t_function*> functions = tservice->get_functions();
  vector<t_function*>::const_iterator f_iter;

  indent(s_service) << "protected" << '\n';
  indent_up();

  indent(s_service) << "// Iface" << '\n';
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
    string funname = (*f_iter)->get_name();
    generate_delphi_doc(s_service, *f_iter);
    indent(s_service) << function_signature(*f_iter, false) << '\n';
  }

  if( async_) {
    indent(s_service) << '\n';
    indent(s_service) << "// IAsync" << '\n';
    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
      string funname = (*f_iter)->get_name();
      generate_delphi_doc(s_service, *f_iter);
      indent(s_service) << function_signature(*f_iter, true) << '\n';
    }
  }

  indent_down();

  indent(s_service) << "public" << '\n';
  indent_up();

  string full_cls = normalize_clsnm(service_name_, "T") + ".TClient";

  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
    string funname = (*f_iter)->get_name();

    vector<t_field*>::const_iterator fld_iter;
    t_struct* arg_struct = (*f_iter)->get_arglist();
    const vector<t_field*>& fields = arg_struct->get_members();

    // one for sync only, two for async+sync
    int mode = async_ ? 1 : 0;
    while( mode >= 0) {
      bool for_async = (mode != 0);
      mode--;

      indent_impl(s_service_impl) << function_signature(*f_iter, for_async, full_cls) << '\n';
      indent_impl(s_service_impl) << "begin" << '\n';
      indent_up_impl();

      t_type* ttype = (*f_iter)->get_returntype();
      if( for_async) {
        if (is_void(ttype)) {
           // Delphi forces us to specify a type with IFuture<T>, so we use Integer=0 for void methods
          indent_impl(s_service_impl) << "result := TTask.Future<System.Integer>(function: System.Integer" << '\n';
        } else {
          string rettype = type_name(ttype, false, true, false, true);
          indent_impl(s_service_impl) << "result := TTask.Future<" << rettype << ">(function: " << rettype << '\n';
        }
        indent_impl(s_service_impl) << "begin" << '\n';
        indent_up_impl();
      }

      indent_impl(s_service_impl) << "send_" << funname << "(";

      bool first = true;
      for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
        if (first) {
          first = false;
        } else {
          s_service_impl << ", ";
        }
        s_service_impl << normalize_name((*fld_iter)->get_name());
      }
      s_service_impl << ");" << '\n';

      if (!(*f_iter)->is_oneway()) {
        s_service_impl << indent_impl();
        if (!(*f_iter)->get_returntype()->is_void()) {
          s_service_impl << "Result := ";
        }
        s_service_impl << "recv_" << funname << "();" << '\n';
      }

      if( for_async) {
        if (is_void(ttype)) {
          indent_impl(s_service_impl) << "Result := 0;" << '\n';  // no IFuture<void> in Delphi
        }
        indent_down_impl();
        indent_impl(s_service_impl) << "end);" << '\n';
      }

      indent_down_impl();
      indent_impl(s_service_impl) << "end;" << '\n' << '\n';
    }

    t_function send_function(g_type_void,
                             string("send_") + (*f_iter)->get_name(),
                             (*f_iter)->get_arglist());

    string argsname = (*f_iter)->get_name() + "_args";
    string args_clsnm = normalize_clsnm(argsname, "T");
    string args_intfnm = normalize_clsnm(argsname, "I");

    string argsvar = tmp("_args");
    string msgvar = tmp("_msg");

    indent(s_service) << function_signature(&send_function, false) << '\n';
    indent_impl(s_service_impl) << function_signature(&send_function, false, full_cls) << '\n';
    indent_impl(s_service_impl) << "var" << '\n';
    indent_up_impl();
    indent_impl(s_service_impl) << argsvar << " : " << args_intfnm << ";" << '\n';
    indent_impl(s_service_impl) << msgvar << " : Thrift.Protocol.TThriftMessage;" << '\n';
    indent_down_impl();
    indent_impl(s_service_impl) << "begin" << '\n';
    indent_up_impl();

    indent_impl(s_service_impl) << "seqid_ := seqid_ + 1;" << '\n';
    indent_impl(s_service_impl) << "Thrift.Protocol.Init( " << msgvar << ", '" << funname
                                << "', " << ((*f_iter)->is_oneway() ? "TMessageType.Oneway"
                                                                    : "TMessageType.Call")
                                << ", seqid_);" << '\n';

    indent_impl(s_service_impl) << "oprot_.WriteMessageBegin( " << msgvar << " );" << '\n';
    indent_impl(s_service_impl) << argsvar << " := " << args_clsnm << "Impl.Create();" << '\n';

    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
      indent_impl(s_service_impl) << argsvar << "." << prop_name(*fld_iter)
                                  << " := " << normalize_name((*fld_iter)->get_name()) << ";"
                                  << '\n';
    }
    indent_impl(s_service_impl) << argsvar << ".Write(oprot_);" << '\n';
    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
      indent_impl(s_service_impl) << argsvar << "." << prop_name(*fld_iter)
                                  << " := " << empty_value((*fld_iter)->get_type()) << ";" << '\n';
    }

    indent_impl(s_service_impl) << "oprot_.WriteMessageEnd();" << '\n';
    indent_impl(s_service_impl) << "oprot_.Transport.Flush();" << '\n';

    indent_down_impl();
    indent_impl(s_service_impl) << "end;" << '\n' << '\n';

    if (!(*f_iter)->is_oneway()) {
      string org_resultname = (*f_iter)->get_name() + "_result";
      string result_clsnm = normalize_clsnm(org_resultname, "T");
      string result_intfnm = normalize_clsnm(org_resultname, "I");

      t_struct noargs(program_);
      t_function recv_function((*f_iter)->get_returntype(),
                               string("recv_") + (*f_iter)->get_name(),
                               &noargs,
                               (*f_iter)->get_xceptions());

      t_struct* xs = (*f_iter)->get_xceptions();
      const std::vector<t_field*>& xceptions = xs->get_members();

      string exceptvar = tmp("_ex");
      string appexvar = tmp("_ax");
      string retvar = tmp("_ret");

      indent(s_service) << function_signature(&recv_function, false) << '\n';
      indent_impl(s_service_impl) << function_signature(&recv_function, false, full_cls) << '\n';
      indent_impl(s_service_impl) << "var" << '\n';
      indent_up_impl();
      indent_impl(s_service_impl) << msgvar << " : Thrift.Protocol.TThriftMessage;" << '\n';
      if (xceptions.size() > 0) {
        indent_impl(s_service_impl) << exceptvar << " : Exception;" << '\n';
      }
      indent_impl(s_service_impl) << appexvar << " : TApplicationException;" << '\n';
      indent_impl(s_service_impl) << retvar << " : " << result_intfnm << ";" << '\n';

      indent_down_impl();
      indent_impl(s_service_impl) << "begin" << '\n';
      indent_up_impl();
      indent_impl(s_service_impl) << msgvar << " := iprot_.ReadMessageBegin();" << '\n';
      indent_impl(s_service_impl) << "if (" << msgvar << ".Type_ = TMessageType.Exception) then begin" << '\n';
      indent_up_impl();
      indent_impl(s_service_impl) << appexvar << " := TApplicationException.Read(iprot_);" << '\n';
      indent_impl(s_service_impl) << "iprot_.ReadMessageEnd();" << '\n';
      indent_impl(s_service_impl) << "raise " << appexvar << ";" << '\n';
      indent_down_impl();
      indent_impl(s_service_impl) << "end;" << '\n';

      indent_impl(s_service_impl) << retvar << " := " << result_clsnm << "Impl.Create();" << '\n';
      indent_impl(s_service_impl) << retvar << ".Read(iprot_);" << '\n';
      indent_impl(s_service_impl) << "iprot_.ReadMessageEnd();" << '\n';

      if (!(*f_iter)->get_returntype()->is_void()) {
        indent_impl(s_service_impl) << "if (" << retvar << ".__isset_success) then begin" << '\n';
        indent_up_impl();
        indent_impl(s_service_impl) << "Result := " << retvar << ".Success;" << '\n';
        t_type* type = (*f_iter)->get_returntype();
        if (type->is_struct() || type->is_xception() || type->is_map() || type->is_list()
            || type->is_set()) {
          indent_impl(s_service_impl) << retvar << ".Success := nil;" << '\n';
        }
        indent_impl(s_service_impl) << "Exit;" << '\n';
        indent_down_impl();
        indent_impl(s_service_impl) << "end;" << '\n';
      }

      vector<t_field*>::const_iterator x_iter;
      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
        indent_impl(s_service_impl) << "if (" << retvar << "." << prop_name(*x_iter, false, "__isset_")
                                    << ") then begin" << '\n';
        indent_up_impl();
        indent_impl(s_service_impl) << exceptvar << " := " << retvar << "." << prop_name(*x_iter)
                                    << ".CreateException;" << '\n';
        indent_impl(s_service_impl) << "raise " << exceptvar << ";" << '\n';
        indent_down_impl();
        indent_impl(s_service_impl) << "end;" << '\n';
      }

      if (!(*f_iter)->get_returntype()->is_void()) {
        indent_impl(s_service_impl)
            << "raise TApplicationExceptionMissingResult.Create('"
            << (*f_iter)->get_name() << " failed: unknown result');" << '\n';
      }

      indent_down_impl();
      indent_impl(s_service_impl) << "end;" << '\n' << '\n';
    }
  }

  indent_down();
  indent(s_service) << "end;"
                    << render_deprecation_attribute( tservice->annotations_, " {", "}")
                    << '\n' << '\n';
}