1515 */
1616package feign ;
1717
18+ import dagger .Lazy ;
1819import feign .Request .Options ;
1920import feign .codec .DecodeException ;
2021import feign .codec .Decoder ;
2122import feign .codec .ErrorDecoder ;
23+ import feign .codec .IncrementalDecoder ;
2224
2325import javax .inject .Inject ;
26+ import javax .inject .Named ;
2427import javax .inject .Provider ;
2528import java .io .IOException ;
29+ import java .io .Reader ;
30+ import java .util .concurrent .Executor ;
2631import java .util .concurrent .TimeUnit ;
2732
2833import static feign .FeignException .errorExecuting ;
3237
3338abstract class MethodHandler {
3439
40+ /**
41+ * same approach as retrofit: temporarily rename threads
42+ */
43+ static final String THREAD_PREFIX = "Feign-" ;
44+ static final String IDLE_THREAD_NAME = THREAD_PREFIX + "Idle" ;
45+
3546 /**
3647 * Those using guava will implement as {@code Function<Object[], RequestTemplate>}.
3748 */
@@ -42,12 +53,15 @@ static interface BuildTemplateFromArgs {
4253 static class Factory {
4354
4455 private final Client client ;
56+ private final Lazy <Executor > httpExecutor ;
4557 private final Provider <Retryer > retryer ;
4658 private final Logger logger ;
4759 private final Logger .Level logLevel ;
4860
49- @ Inject Factory (Client client , Provider <Retryer > retryer , Logger logger , Logger .Level logLevel ) {
61+ @ Inject Factory (Client client , @ Named ("http" ) Lazy <Executor > httpExecutor , Provider <Retryer > retryer , Logger logger ,
62+ Logger .Level logLevel ) {
5063 this .client = checkNotNull (client , "client" );
64+ this .httpExecutor = checkNotNull (httpExecutor , "httpExecutor" );
5165 this .retryer = checkNotNull (retryer , "retryer" );
5266 this .logger = checkNotNull (logger , "logger" );
5367 this .logLevel = checkNotNull (logLevel , "logLevel" );
@@ -58,6 +72,78 @@ public MethodHandler create(Target<?> target, MethodMetadata md, BuildTemplateFr
5872 return new SynchronousMethodHandler (target , client , retryer , logger , logLevel , md , buildTemplateFromArgs , options ,
5973 decoder , errorDecoder );
6074 }
75+
76+ public MethodHandler create (Target <?> target , MethodMetadata md , BuildTemplateFromArgs buildTemplateFromArgs ,
77+ Options options , IncrementalDecoder .TextStream <?> incrementalCallbackDecoder ,
78+ ErrorDecoder errorDecoder ) {
79+ return new IncrementalCallbackMethodHandler (target , client , retryer , logger , logLevel , md , buildTemplateFromArgs ,
80+ options , incrementalCallbackDecoder , errorDecoder , httpExecutor );
81+ }
82+ }
83+
84+ static final class IncrementalCallbackMethodHandler extends MethodHandler {
85+ private final Lazy <Executor > httpExecutor ;
86+ private final IncrementalDecoder .TextStream <?> incDecoder ;
87+
88+ private IncrementalCallbackMethodHandler (Target <?> target , Client client , Provider <Retryer > retryer , Logger logger ,
89+ Logger .Level logLevel , MethodMetadata metadata ,
90+ BuildTemplateFromArgs buildTemplateFromArgs , Options options ,
91+ IncrementalDecoder .TextStream <?> incDecoder , ErrorDecoder errorDecoder ,
92+ Lazy <Executor > httpExecutor ) {
93+ super (target , client , retryer , logger , logLevel , metadata , buildTemplateFromArgs , options , errorDecoder );
94+ this .httpExecutor = checkNotNull (httpExecutor , "httpExecutor for %s" , target );
95+ this .incDecoder = checkNotNull (incDecoder , "incrementalCallbackDecoder for %s" , target );
96+ }
97+
98+ @ Override public Object invoke (final Object [] argv ) throws Throwable {
99+ httpExecutor .get ().execute (new Runnable () {
100+ @ Override public void run () {
101+ Error error = null ;
102+ Object arg = argv [metadata .incrementalCallbackIndex ()];
103+ IncrementalCallback <Object > incrementalCallback = IncrementalCallback .class .cast (arg );
104+ try {
105+ IncrementalCallbackMethodHandler .super .invoke (argv );
106+ incrementalCallback .onSuccess ();
107+ } catch (Error cause ) {
108+ // assign to a variable in case .onFailure throws a RTE
109+ error = cause ;
110+ incrementalCallback .onFailure (cause );
111+ } catch (Throwable cause ) {
112+ incrementalCallback .onFailure (cause );
113+ } finally {
114+ Thread .currentThread ().setName (IDLE_THREAD_NAME );
115+ if (error != null )
116+ throw error ;
117+ }
118+ }
119+ });
120+ return null ; // void.
121+ }
122+
123+ @ Override protected Object decode (Object [] argv , Response response ) throws Throwable {
124+ Object arg = argv [metadata .incrementalCallbackIndex ()];
125+ IncrementalCallback <Object > incrementalCallback = IncrementalCallback .class .cast (arg );
126+ if (metadata .decodeInto ().equals (Response .class )) {
127+ incrementalCallback .onNext (response );
128+ } else if (metadata .decodeInto () != Void .class ) {
129+ Response .Body body = response .body ();
130+ if (body == null )
131+ return null ;
132+ Reader reader = body .asReader ();
133+ try {
134+ incDecoder .decode (reader , metadata .decodeInto (), incrementalCallback );
135+ } finally {
136+ ensureClosed (body );
137+ }
138+ }
139+ return null ; // void
140+ }
141+
142+ @ Override protected Request targetRequest (RequestTemplate template ) {
143+ Request request = super .targetRequest (template );
144+ Thread .currentThread ().setName (THREAD_PREFIX + metadata .configKey ());
145+ return request ;
146+ }
61147 }
62148
63149 static final class SynchronousMethodHandler extends MethodHandler {
@@ -125,10 +211,8 @@ public Object invoke(Object[] argv) throws Throwable {
125211 }
126212 }
127213
128- public Object executeAndDecode (Object [] argv , RequestTemplate template )
129- throws Throwable {
130- // create the request from a mutable copy of the input template.
131- Request request = target .apply (new RequestTemplate (template ));
214+ public Object executeAndDecode (Object [] argv , RequestTemplate template ) throws Throwable {
215+ Request request = targetRequest (template );
132216
133217 if (logLevel .ordinal () > Logger .Level .NONE .ordinal ()) {
134218 logger .logRequest (target , logLevel , request );
@@ -159,5 +243,9 @@ public Object executeAndDecode(Object[] argv, RequestTemplate template)
159243 }
160244 }
161245
246+ protected Request targetRequest (RequestTemplate template ) {
247+ return target .apply (new RequestTemplate (template ));
248+ }
249+
162250 protected abstract Object decode (Object [] argv , Response response ) throws Throwable ;
163251}
0 commit comments