Uploaded image for project: 'Thrift'
  1. Thrift
  2. THRIFT-5762

Expose service result objects in Java

    XMLWordPrintableJSON

Details

    • New Feature
    • Status: Resolved
    • Major
    • Resolution: Fixed
    • None
    • 0.21.0
    • Java - Compiler
    • None

    Description

      Some libraries want to bypass the TServer class and handle the full
      service startup manually. For example when building a service that hosts
      multiple thrift services where the IFace type is unknown when handling a
      request.

      For example when you host multiple services on top of netty and through
      an HTTP path you want to route to the correct thrift service. In this
      situation you treat can treat an IFace as an Object and use the
      `getProcessMapView()` method to parse a byte array into a thrift message
      and pass let the `AsyncProcessFunction` handle the invocation.

      To return a correct thrift response it's necessary to write the
      `

      {service_name}_result` that contains the response args.
      While it is possible to get an incoming args object from the
      (Async)ProcessFunction its unfortunately not possible to get
      a result object without using reflection.

      This PR extends the (Async)ProcessFunction by adding a
      `getEmptyResultInstance` method that returns a new generic `A` (answer)
      that matches the `{service_name}

      _result` object.

      This allows thrift users to write the following processing code:

      <I> void handleRequest(
              TProtocol in,
              TProtocol out,
              TBaseAsyncProcessor<I> processor,
              I asyncIface
      ) throws TException {
          final Map<String, AsyncProcessFunction<Object, TBase<?, ?>, TBase<?, ?>, TBase<?, ?>>> processMap = (Map) processor.getProcessMapView();
          final var msg = in.readMessageBegin();
          final var fn = processMap.get(msg.name);
      
          final var args = fn.getEmptyArgsInstance();
          args.read(in);
          in.readMessageEnd();
      
          if (fn.isOneway()) {
              return;
          }
      
          fn.start(asyncIface, args, new AsyncMethodCallback<>() {
              @Override
              public void onComplete(TBase<?, ?> o) {
                  try {
                      out.writeMessageBegin(new TMessage(fn.getMethodName(), TMessageType.REPLY, msg.getSeqid()));
                      final var response_result = fn.getEmptyResultInstance();
                      final var success_field = response_result.fieldForId(SUCCESS_ID);
                      ((TBase) response_result).setFieldValue(success_field, o);
                      response_result.write(out);
                      out.writeMessageEnd();
                      out.getTransport().flush();
                  } catch (TException e) {
                      throw new RuntimeException(e);
                  }
              }
      
              @Override
              public void onError(Exception e) {
                  try {
                      out.writeMessageBegin(new TMessage(fn.getMethodName(), TMessageType.EXCEPTION, msg.getSeqid()));
                      ((TApplicationException) e).write(out);
                      out.writeMessageEnd();
                      out.getTransport().flush();
                  } catch (TException ex) {
                      throw new RuntimeException(ex);
                  }
              }
          });
      }
      

      The above example code doesn't need any reference to the original types
      and can dynamically create the correct objects to return a correct
      response.

      Attachments

        Activity

          People

            thomasbruggink Thomas Bruggink
            thomasbruggink Thomas Bruggink
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Time Tracking

                Estimated:
                Original Estimate - Not Specified
                Not Specified
                Remaining:
                Remaining Estimate - 0h
                0h
                Logged:
                Time Spent - 2h
                2h