Skip to content

Commit 1e3ed1d

Browse files
bfgslandelle
authored andcommittedFeb 26, 2019
Retrofit improvements (#1615)
* Don't try to cancel already completed future. If AHC is used concurrently with rxjava retrofit call adapter using `flatMap(Function, maxConcurrency)` warning messages are being logged about future not being able to be cancelled, because it's already complete. This patch remedies situation by first checking whether future has been already completed. * Added ability to fetch async http client instance from a supplier. Sometimes it's handy not to tie call factory to particular http client instance, but to fetch it from a supplier. This patch adds ability to fetch http client from a supplier while retaining ability to use particular, fixed http client instance.
1 parent a00d469 commit 1e3ed1d

File tree

3 files changed

+79
-9
lines changed

3 files changed

+79
-9
lines changed
 

‎extras/retrofit2/src/main/java/org/asynchttpclient/extras/retrofit/AsyncHttpClientCall.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ public void enqueue(Callback responseCallback) {
149149
@Override
150150
public void cancel() {
151151
val future = futureRef.get();
152-
if (future != null) {
152+
if (future != null && !future.isDone()) {
153153
if (!future.cancel(true)) {
154154
log.warn("Cannot cancel future: {}", future);
155155
}

‎extras/retrofit2/src/main/java/org/asynchttpclient/extras/retrofit/AsyncHttpClientCallFactory.java

+25-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
import org.asynchttpclient.AsyncHttpClient;
1919

2020
import java.util.List;
21+
import java.util.Optional;
2122
import java.util.function.Consumer;
23+
import java.util.function.Supplier;
2224

2325
import static org.asynchttpclient.extras.retrofit.AsyncHttpClientCall.runConsumers;
2426

@@ -30,10 +32,18 @@
3032
public class AsyncHttpClientCallFactory implements Call.Factory {
3133
/**
3234
* {@link AsyncHttpClient} in use.
35+
*
36+
* @see #httpClientSupplier
3337
*/
34-
@NonNull
38+
@Getter(AccessLevel.NONE)
3539
AsyncHttpClient httpClient;
3640

41+
/**
42+
* Supplier of {@link AsyncHttpClient}, takes precedence over {@link #httpClient}.
43+
*/
44+
@Getter(AccessLevel.NONE)
45+
Supplier<AsyncHttpClient> httpClientSupplier;
46+
3747
/**
3848
* List of {@link Call} builder customizers that are invoked just before creating it.
3949
*/
@@ -52,4 +62,17 @@ public Call newCall(Request request) {
5262
// create a call
5363
return callBuilder.build();
5464
}
55-
}
65+
66+
/**
67+
* {@link AsyncHttpClient} in use by this factory.
68+
*
69+
* @return
70+
*/
71+
public AsyncHttpClient getHttpClient() {
72+
return Optional.ofNullable(httpClientSupplier)
73+
.map(Supplier::get)
74+
.map(Optional::of)
75+
.orElseGet(() -> Optional.ofNullable(httpClient))
76+
.orElseThrow(() -> new IllegalStateException("HTTP client is not set."));
77+
}
78+
}

‎extras/retrofit2/src/test/java/org/asynchttpclient/extras/retrofit/AsyncHttpClientCallFactoryTest.java

+53-6
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,12 @@ void shouldApplyAllConsumersToCallBeingConstructed() {
109109
};
110110

111111
Consumer<AsyncHttpClientCall.AsyncHttpClientCallBuilder> callCustomizer = callBuilder ->
112-
callBuilder
113-
.requestCustomizer(requestCustomizer)
114-
.requestCustomizer(rb -> log.warn("I'm customizing: {}", rb))
115-
.onRequestSuccess(createConsumer(numRequestSuccess))
116-
.onRequestFailure(createConsumer(numRequestFailure))
117-
.onRequestStart(createConsumer(numRequestStart));
112+
callBuilder
113+
.requestCustomizer(requestCustomizer)
114+
.requestCustomizer(rb -> log.warn("I'm customizing: {}", rb))
115+
.onRequestSuccess(createConsumer(numRequestSuccess))
116+
.onRequestFailure(createConsumer(numRequestFailure))
117+
.onRequestStart(createConsumer(numRequestStart));
118118

119119
// create factory
120120
val factory = AsyncHttpClientCallFactory.builder()
@@ -151,4 +151,51 @@ void shouldApplyAllConsumersToCallBeingConstructed() {
151151
assertNotNull(call.getRequestCustomizers());
152152
assertTrue(call.getRequestCustomizers().size() == 2);
153153
}
154+
155+
@Test(expectedExceptions = IllegalStateException.class, expectedExceptionsMessageRegExp = "HTTP client is not set.")
156+
void shouldThrowISEIfHttpClientIsNotDefined() {
157+
// given
158+
val factory = AsyncHttpClientCallFactory.builder()
159+
.build();
160+
161+
// when
162+
val httpClient = factory.getHttpClient();
163+
164+
// then
165+
assertNull(httpClient);
166+
}
167+
168+
@Test
169+
void shouldUseHttpClientInstanceIfSupplierIsNotAvailable() {
170+
// given
171+
val httpClientA = mock(AsyncHttpClient.class);
172+
173+
val factory = AsyncHttpClientCallFactory.builder()
174+
.httpClient(httpClientA)
175+
.build();
176+
177+
// when
178+
val usedHttpClient = factory.getHttpClient();
179+
180+
// then
181+
assertTrue(usedHttpClient == httpClientA);
182+
}
183+
184+
@Test
185+
void shouldPreferHttpClientSupplierOverHttpClient() {
186+
// given
187+
val httpClientA = mock(AsyncHttpClient.class);
188+
val httpClientB = mock(AsyncHttpClient.class);
189+
190+
val factory = AsyncHttpClientCallFactory.builder()
191+
.httpClient(httpClientA)
192+
.httpClientSupplier(() -> httpClientB)
193+
.build();
194+
195+
// when
196+
val usedHttpClient = factory.getHttpClient();
197+
198+
// then
199+
assertTrue(usedHttpClient == httpClientB);
200+
}
154201
}

0 commit comments

Comments
 (0)
Please sign in to comment.