Details
-
New Feature
-
Status: Resolved
-
Major
-
Resolution: Fixed
-
None
-
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
`
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.