void t_cocoa_generator::generate_cocoa_service_server_implementation()

in thrift/compiler/generate/t_cocoa_generator.cc [1989:2173]


void t_cocoa_generator::generate_cocoa_service_server_implementation(
    std::ofstream& out, const t_service* tservice) {
  out << "@implementation " << cocoa_prefix_ << tservice->name() << "Processor"
      << std::endl;
  indent_up();

  // initializer
  out << std::endl;
  out << "- (id) initWith" << tservice->name() << ": (id <" << cocoa_prefix_
      << tservice->name() << ">) service" << std::endl;
  scope_up(out);
  out << indent() << "self = [super init];" << std::endl;
  out << indent() << "if (!self) {" << std::endl;
  out << indent() << "  return nil;" << std::endl;
  out << indent() << "}" << std::endl;
  // out << indent() << "mService = [service retain_stub];" << std::endl;
  // out << indent() << "mMethodMap = [[NSMutableDictionary dictionary]
  // retain_stub];" << std::endl;

  // generate method std::map for routing incoming calls
  for (const auto* function : tservice->get_functions()) {
    const std::string& funname = function->name();
    scope_up(out);
    out << indent() << "SEL s = @selector(process_" << funname
        << "_withSequenceID:inProtocol:outProtocol:);" << std::endl;
    out << indent()
        << "NSMethodSignature * sig = [self methodSignatureForSelector: s];"
        << std::endl;
    out << indent()
        << "NSInvocation * invocation = [NSInvocation invocationWithMethodSignature: sig];"
        << std::endl;
    out << indent() << "[invocation setSelector: s];" << std::endl;
    out << indent() << "[invocation retainArguments];" << std::endl;
    out << indent() << "[mMethodMap setValue: invocation forKey: @\"" << funname
        << "\"];" << std::endl;
    scope_down(out);
  }
  out << indent() << "return self;" << std::endl;
  scope_down(out);

  // implementation of the 'service' method which returns the service associated
  // with this processor
  out << std::endl;
  out << indent() << "- (id<" << cocoa_prefix_ << tservice->name()
      << ">) service" << std::endl;
  out << indent() << "{" << std::endl;
  out << indent() << "  return [[mService retain_stub] autorelease_stub];"
      << std::endl;
  out << indent() << "}" << std::endl;

  // implementation of the TProcess method, which dispatches the incoming call
  // using the method std::map
  out << std::endl;
  out << indent()
      << "- (BOOL) processOnInputProtocol: (id <TProtocol>) inProtocol"
      << std::endl;
  out << indent()
      << "                 outputProtocol: (id <TProtocol>) outProtocol"
      << std::endl;
  out << indent() << "{" << std::endl;
  out << indent() << "  NSString * messageName;" << std::endl;
  out << indent() << "  int messageType;" << std::endl;
  out << indent() << "  int seqID;" << std::endl;
  out << indent() << "  [inProtocol readMessageBeginReturningName: &messageName"
      << std::endl;
  out << indent() << "                                       type: &messageType"
      << std::endl;
  out << indent() << "                                 sequenceID: &seqID];"
      << std::endl;
  out << indent()
      << "  NSInvocation * invocation = [mMethodMap valueForKey: messageName];"
      << std::endl;
  out << indent() << "  if (invocation == nil) {" << std::endl;
  out << indent()
      << "    [TProtocolUtil skipType: TType_STRUCT onProtocol: inProtocol];"
      << std::endl;
  out << indent() << "    [inProtocol readMessageEnd];" << std::endl;
  out << indent()
      << "    TApplicationException * x = [TApplicationException exceptionWithType: TApplicationException_UNKNOWN_METHOD reason: [NSString stringWithFormat: @\"Invalid method name: '%@'\", messageName]];"
      << std::endl;
  out << indent() << "    [outProtocol writeMessageBeginWithName: messageName"
      << std::endl;
  out << indent()
      << "                                      type: TMessageType_EXCEPTION"
      << std::endl;
  out << indent() << "                                sequenceID: seqID];"
      << std::endl;
  out << indent() << "    [x write: outProtocol];" << std::endl;
  out << indent() << "    [outProtocol writeMessageEnd];" << std::endl;
  out << indent() << "    [[outProtocol transport] flush];" << std::endl;
  out << indent() << "    return YES;" << std::endl;
  out << indent() << "  }" << std::endl;
  out << indent() << "  // NSInvocation does not conform to NSCopying protocol"
      << std::endl;
  out << indent()
      << "  NSInvocation * i = [NSInvocation invocationWithMethodSignature: [invocation methodSignature]];"
      << std::endl;
  out << indent() << "  [i setSelector: [invocation selector]];" << std::endl;
  out << indent() << "  [i setArgument: &seqID atIndex: 2];" << std::endl;
  out << indent() << "  [i setArgument: &inProtocol atIndex: 3];" << std::endl;
  out << indent() << "  [i setArgument: &outProtocol atIndex: 4];" << std::endl;
  out << indent() << "  [i setTarget: self];" << std::endl;
  out << indent() << "  [i invoke];" << std::endl;
  out << indent() << "  return YES;" << std::endl;
  out << indent() << "}" << std::endl;

  // generate a process_XXXX method for each service function, which reads args,
  // calls the service, and writes results
  for (const auto* function : tservice->get_functions()) {
    out << std::endl;
    const std::string& funname = function->name();
    out << indent() << "- (void) process_" << funname
        << "_withSequenceID: (int32_t) seqID inProtocol: (id<TProtocol>) inProtocol outProtocol: (id<TProtocol>) outProtocol"
        << std::endl;
    scope_up(out);
    std::string argstype =
        cocoa_prefix_ + function_args_helper_struct_type(function);
    out << indent() << argstype << " * args = [[" << argstype
        << " alloc] init];" << std::endl;
    out << indent() << "[args read: inProtocol];" << std::endl;
    out << indent() << "[inProtocol readMessageEnd];" << std::endl;

    // prepare the result if not oneway
    if (function->qualifier() != t_function_qualifier::one_way) {
      std::string resulttype =
          cocoa_prefix_ + function_result_helper_struct_type(function);
      out << indent() << resulttype << " * result = [[" << resulttype
          << " alloc] init];" << std::endl;
    }

    // make the call to the actual service object
    out << indent();
    if (!function->get_returntype()->is_void()) {
      out << "[result setSuccess: ";
    }
    out << "[mService " << funname;
    bool first = true;
    for (const auto& param : function->get_paramlist()->fields()) {
      const std::string& fieldName = param.name();
      if (first) {
        first = false;
        out << ": [args " << fieldName << "]";
      } else {
        out << " " << fieldName << ": [args " << fieldName << "]";
      }
    }
    out << "]";
    if (!function->get_returntype()->is_void()) {
      out << "]";
    }
    out << ";" << std::endl;

    // write out the result if not oneway
    if (function->qualifier() != t_function_qualifier::one_way) {
      out << indent() << "[outProtocol writeMessageBeginWithName: @\""
          << funname << "\"" << std::endl;
      out << indent()
          << "                                  type: TMessageType_REPLY"
          << std::endl;
      out << indent() << "                            sequenceID: seqID];"
          << std::endl;
      out << indent() << "[result write: outProtocol];" << std::endl;
      out << indent() << "[outProtocol writeMessageEnd];" << std::endl;
      out << indent() << "[[outProtocol transport] flush];" << std::endl;
      out << indent() << "[result release_stub];" << std::endl;
    }
    out << indent() << "[args release_stub];" << std::endl;

    scope_down(out);
  }

  // dealloc
  out << std::endl;
  out << "- (void) dealloc" << std::endl;
  scope_up(out);
  out << indent() << "[mService release_stub];" << std::endl;
  out << indent() << "[mMethodMap release_stub];" << std::endl;
  out << indent() << "[super dealloc_stub];" << std::endl;
  scope_down(out);
  out << std::endl;

  indent_down();

  out << "@end" << std::endl << std::endl;
}