diff --git a/README.md b/README.md index ab43264..28187fb 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ The Xenon View Java SDK is the Java SDK to interact with [XenonView](https://xen
## What"s New +* v0.1.8 - On socket timeout, close all cached connections and start new see #185024471. * v0.1.7 - Add options for term/price for all subscription related calls. * v0.1.6 - Add initial subscriptions options for term/price. * v0.1.5 - Fix typo diff --git a/lib/build.gradle b/lib/build.gradle index 9bbc047..b2539ab 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -29,7 +29,7 @@ repositories { mavenCentral() } -project.version = "0.1.7" +project.version = "0.1.8" project.description = 'The Xenon View Java SDK is the Java SDK to interact with https://xenonview.com.' project.group = "io.github.xenonview-com" project.archivesBaseName = 'xenon-view-sdk' diff --git a/lib/src/main/java/xenon/view/sdk/api/fetch/JsonFetcher.java b/lib/src/main/java/xenon/view/sdk/api/fetch/JsonFetcher.java index dede3f7..4e420c7 100644 --- a/lib/src/main/java/xenon/view/sdk/api/fetch/JsonFetcher.java +++ b/lib/src/main/java/xenon/view/sdk/api/fetch/JsonFetcher.java @@ -24,16 +24,25 @@ public class JsonFetcher implements Fetchable { private OkHttpClient client; private OkHttpClient.Builder builder = new OkHttpClient.Builder(); + public interface NewHttpClientPointer { + OkHttpClient newClient(); + } + private static OkHttpClient newClient(){ + return new OkHttpClient(); + } + private NewHttpClientPointer httpClientMaker = JsonFetcher::newClient; + public JsonFetcher(){ - client = new OkHttpClient(); + client = JsonFetcher.newClient(); } - public JsonFetcher(OkHttpClient _client){ - client = _client; + public JsonFetcher(NewHttpClientPointer _clientMaker){ + httpClientMaker = _clientMaker; + client = httpClientMaker.newClient(); } - public JsonFetcher(OkHttpClient.Builder _builder, OkHttpClient _client){ - this(_client); + public JsonFetcher(OkHttpClient.Builder _builder, NewHttpClientPointer _clientMaker){ + this(_clientMaker); builder = _builder; } @@ -79,6 +88,9 @@ public CompletableFuture fetch(JSONObject data) throws JSONException{ @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { //HTTP request exception + client.dispatcher().executorService().shutdown(); + client.connectionPool().evictAll(); + client = httpClientMaker.newClient(); completableFuture.completeExceptionally(e); } diff --git a/lib/src/test/java/xenon/view/sdk/api/fetch/JsonFetcherTest.java b/lib/src/test/java/xenon/view/sdk/api/fetch/JsonFetcherTest.java index 4275da1..af8d865 100644 --- a/lib/src/test/java/xenon/view/sdk/api/fetch/JsonFetcherTest.java +++ b/lib/src/test/java/xenon/view/sdk/api/fetch/JsonFetcherTest.java @@ -27,6 +27,7 @@ import java.util.Hashtable; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicReference; import static com.github.paulcwarren.ginkgo4j.Ginkgo4jDSL.*; @@ -58,7 +59,7 @@ public class JsonFetcherTest { AtomicReference> completableFuture = new AtomicReference<>(); BeforeEach(() -> { data.get().put("method", "GET"); - unit.set(new JsonFetcher(client)); + unit.set(new JsonFetcher(()->{return client;})); when(client.newCall(any())).thenAnswer(invocation -> { request.set((Request) invocation.getArguments()[0]); return enqueuer; @@ -112,9 +113,15 @@ public class JsonFetcherTest { }); }); Describe("when the request is not successful", () -> { + Dispatcher theDispatcher = mock(Dispatcher.class); + ExecutorService theService = mock(ExecutorService.class); + ConnectionPool thePool = mock(ConnectionPool.class); BeforeEach(() -> { Call theCall = mock(Call.class); when(theCall.request()).thenReturn(request.get()); + when(client.dispatcher()).thenReturn(theDispatcher); + when(theDispatcher.executorService()).thenReturn(theService); + when(client.connectionPool()).thenReturn(thePool); callback.get().onFailure(theCall, new IOException("{\"response\":\"failed\"}")); }); @@ -124,6 +131,10 @@ public class JsonFetcherTest { return new Json(err.getMessage()); }); }); + It("closes connection pool", () -> { + verify(theService).shutdown(); + verify(thePool).evictAll(); + }); }); Describe("when the request unauthorized", () -> { final Response response = mock(Response.class); @@ -158,9 +169,15 @@ public class JsonFetcherTest { }); }); Describe("when the request errors", () -> { + Dispatcher theDispatcher = mock(Dispatcher.class); + ExecutorService theService = mock(ExecutorService.class); + ConnectionPool thePool = mock(ConnectionPool.class); BeforeEach(() -> { Call theCall = mock(Call.class); when(theCall.request()).thenReturn(request.get()); + when(client.dispatcher()).thenReturn(theDispatcher); + when(theDispatcher.executorService()).thenReturn(theService); + when(client.connectionPool()).thenReturn(thePool); callback.get().onFailure(theCall, new IOException("No Internet Connection")); }); It("rejects the promise", () -> { @@ -169,6 +186,10 @@ public class JsonFetcherTest { return new Json(err.getMessage()); }); }); + It("closes connection pool", () -> { + verify(theService).shutdown(); + verify(thePool).evictAll(); + }); }); Describe("when the request generally errors", () -> { final Response response = mock(Response.class); @@ -233,7 +254,7 @@ public class JsonFetcherTest { data.get().put("body", new JSONObject() {{ put("test", "body"); }}); - unit.set(new JsonFetcher(client)); + unit.set(new JsonFetcher(()->{return client;})); when(client.newCall(any())).thenAnswer(invocation -> { request.set((Request) invocation.getArguments()[0]); return enqueuer; @@ -269,7 +290,7 @@ public class JsonFetcherTest { JSONObject headers = new JSONObject(); headers.put("authorization", "Bearer "); data.get().put("requestHeaders", headers); - unit.set(new JsonFetcher(client)); + unit.set(new JsonFetcher(()->{return client;})); when(client.newCall(any())).thenAnswer(invocation -> { request.set((Request) invocation.getArguments()[0]); return enqueuer; @@ -304,7 +325,7 @@ public class JsonFetcherTest { headers.put("authorization", "Bearer "); data.get().put("requestHeaders", headers); data.get().put("ignore-certificate-errors", true); - unit.set(new JsonFetcher(builder, client)); + unit.set(new JsonFetcher(builder, ()->{return client;})); when(builder.sslSocketFactory(any(), any())).thenReturn(builder); when(builder.hostnameVerifier(any())).thenReturn(builder); when(builder.build()).thenReturn(client);