From e1fe30e672ac3d85da1a900f713ca71df621f755 Mon Sep 17 00:00:00 2001 From: Sasha Bogolii Date: Tue, 21 May 2024 10:36:58 +0300 Subject: [PATCH 1/6] API-7698: Added workaround to fix SocketTimeException in okHttp --- CHANGES.MD | 4 ++ README.md | 4 +- build.gradle | 2 +- src/main/java/com/siftscience/Constants.java | 2 +- .../com/siftscience/SiftMerchantRequest.java | 8 ++- .../java/com/siftscience/SiftRequest.java | 3 +- .../com/siftscience/utils/OkHttpUtils.java | 57 +++++++++++++++++++ .../java/com/siftscience/SiftRequestTest.java | 2 +- 8 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/siftscience/utils/OkHttpUtils.java diff --git a/CHANGES.MD b/CHANGES.MD index a630f59..807284a 100644 --- a/CHANGES.MD +++ b/CHANGES.MD @@ -1,3 +1,7 @@ +3.14.2 (2024-05-20) +================= +- Fixed bug with okHttp causing SocketTimeoutException + 3.14.1 (2024-05-16) ================= - Added support for warnings in Events API diff --git a/README.md b/README.md index 410e822..850d5bb 100644 --- a/README.md +++ b/README.md @@ -13,13 +13,13 @@ Java 1.7 or later. com.siftscience sift-java - 3.14.1 + 3.14.2 ``` ### Gradle ``` dependencies { - compile 'com.siftscience:sift-java:3.14.1' + compile 'com.siftscience:sift-java:3.14.2' } ``` ### Other diff --git a/build.gradle b/build.gradle index 3848753..a8f1db6 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ apply plugin: 'signing' apply plugin: 'java-library-distribution' group = 'com.siftscience' -version = '3.14.1' +version = '3.14.2' repositories { mavenCentral() diff --git a/src/main/java/com/siftscience/Constants.java b/src/main/java/com/siftscience/Constants.java index d955fe0..6e37b7e 100644 --- a/src/main/java/com/siftscience/Constants.java +++ b/src/main/java/com/siftscience/Constants.java @@ -3,6 +3,6 @@ public class Constants { public static final String API_VERSION = "v205"; - public static final String LIB_VERSION = "3.14.1"; + public static final String LIB_VERSION = "3.14.2"; public static final String USER_AGENT_HEADER = String.format("SiftScience/%s sift-java/%s", API_VERSION, LIB_VERSION); } diff --git a/src/main/java/com/siftscience/SiftMerchantRequest.java b/src/main/java/com/siftscience/SiftMerchantRequest.java index 5f08055..c89597b 100644 --- a/src/main/java/com/siftscience/SiftMerchantRequest.java +++ b/src/main/java/com/siftscience/SiftMerchantRequest.java @@ -1,6 +1,7 @@ package com.siftscience; import com.siftscience.exception.MerchantAPIException; +import com.siftscience.utils.OkHttpUtils; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; import okhttp3.Request; @@ -45,13 +46,14 @@ protected void modifyRequestBuilder(Request.Builder builder) { public T send() throws IOException { fieldSet.validate(); - Request.Builder okRequestBuilder = new Request.Builder().addHeader("User-Agent", USER_AGENT_HEADER).url(this.url()); + Request.Builder okRequestBuilder = + new Request.Builder().addHeader("User-Agent", USER_AGENT_HEADER).url(this.url()); modifyRequestBuilder(okRequestBuilder); Request request = okRequestBuilder.build(); - T response = buildResponse(okClient.newCall(request).execute(), fieldSet); + T response = buildResponse(OkHttpUtils.execute(request, okClient), fieldSet); if (!response.isOk()) { - throw new MerchantAPIException(response.getApiErrorMessage()); + throw new MerchantAPIException(response.getApiErrorMessage()); } return response; diff --git a/src/main/java/com/siftscience/SiftRequest.java b/src/main/java/com/siftscience/SiftRequest.java index 1bb4d65..2d064db 100644 --- a/src/main/java/com/siftscience/SiftRequest.java +++ b/src/main/java/com/siftscience/SiftRequest.java @@ -1,6 +1,7 @@ package com.siftscience; import com.siftscience.exception.*; +import com.siftscience.utils.OkHttpUtils; import okhttp3.*; import java.io.IOException; @@ -46,7 +47,7 @@ public T send() throws IOException { Request.Builder okRequestBuilder = new Request.Builder().addHeader("User-Agent", USER_AGENT_HEADER).url(this.url()); modifyRequestBuilder(okRequestBuilder); Request request = okRequestBuilder.build(); - T response = buildResponse(okClient.newCall(request).execute(), fieldSet); + T response = buildResponse(OkHttpUtils.execute(request, okClient), fieldSet); // If not successful but no exception happened yet, dig deeper into the response so we // can manually throw an appropriate exception. diff --git a/src/main/java/com/siftscience/utils/OkHttpUtils.java b/src/main/java/com/siftscience/utils/OkHttpUtils.java new file mode 100644 index 0000000..54a77c3 --- /dev/null +++ b/src/main/java/com/siftscience/utils/OkHttpUtils.java @@ -0,0 +1,57 @@ +package com.siftscience.utils; + +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import com.siftscience.exception.SiftException; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.jetbrains.annotations.NotNull; + +public class OkHttpUtils { + + private static final int DEFAULT_TIMEOUT_SEC = 30; + + /** + * There is a bug on okHttp library, + * which causes java.net.SocketTimeoutException from HTTP/2 connection to leave dead okhttp + * clients in pool. + * This utility method is used as a + * workaround + * to enqueue and sync wait for response + * + * @param request - request to send + * @param okClient - client library + * @return - response + */ + public static Response execute(Request request, OkHttpClient okClient) { + CountDownLatch countDownLatch = new CountDownLatch(1); + AtomicReference response = new AtomicReference<>(); + okClient.newCall(request).enqueue(new Callback() { + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + throw new SiftException(e.getMessage()); + } + + @Override + public void onResponse(@NotNull Call call, @NotNull Response httpResponse) { + response.set(httpResponse); + countDownLatch.countDown(); + } + }); + try { + if (countDownLatch.await(DEFAULT_TIMEOUT_SEC, TimeUnit.SECONDS)) { + return response.get(); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new SiftException("Interrupted while waiting for reply from Sift"); + } + throw new SiftException("Timeout while waiting for reply from Sift"); + } +} diff --git a/src/test/java/com/siftscience/SiftRequestTest.java b/src/test/java/com/siftscience/SiftRequestTest.java index 91ad1a9..1c6c985 100644 --- a/src/test/java/com/siftscience/SiftRequestTest.java +++ b/src/test/java/com/siftscience/SiftRequestTest.java @@ -37,7 +37,7 @@ public void testUserAgentHeader() throws Exception { // Verify the request. RecordedRequest recordedRequest = server.takeRequest(); - Assert.assertEquals("SiftScience/v205 sift-java/3.14.1", recordedRequest.getHeader("User-Agent")); + Assert.assertEquals("SiftScience/v205 sift-java/3.14.2", recordedRequest.getHeader("User-Agent")); } } From c9ac65509a335c59d5aca7781ba4363f70faed1b Mon Sep 17 00:00:00 2001 From: Sasha Bogolii Date: Tue, 21 May 2024 11:46:01 +0300 Subject: [PATCH 2/6] API-7698: Fixed error handling --- .../com/siftscience/utils/OkHttpUtils.java | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/siftscience/utils/OkHttpUtils.java b/src/main/java/com/siftscience/utils/OkHttpUtils.java index 54a77c3..f7d36ee 100644 --- a/src/main/java/com/siftscience/utils/OkHttpUtils.java +++ b/src/main/java/com/siftscience/utils/OkHttpUtils.java @@ -1,11 +1,10 @@ package com.siftscience.utils; import java.io.IOException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; +import java.io.InterruptedIOException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; -import com.siftscience.exception.SiftException; import okhttp3.Call; import okhttp3.Callback; import okhttp3.OkHttpClient; @@ -14,8 +13,9 @@ import org.jetbrains.annotations.NotNull; public class OkHttpUtils { + private OkHttpUtils() { - private static final int DEFAULT_TIMEOUT_SEC = 30; + } /** * There is a bug on okHttp library, @@ -29,29 +29,27 @@ public class OkHttpUtils { * @param okClient - client library * @return - response */ - public static Response execute(Request request, OkHttpClient okClient) { - CountDownLatch countDownLatch = new CountDownLatch(1); - AtomicReference response = new AtomicReference<>(); + public static Response execute(Request request, OkHttpClient okClient) throws IOException { + CompletableFuture result = new CompletableFuture<>(); okClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { - throw new SiftException(e.getMessage()); + result.completeExceptionally(e); } @Override public void onResponse(@NotNull Call call, @NotNull Response httpResponse) { - response.set(httpResponse); - countDownLatch.countDown(); + result.complete(httpResponse); } }); try { - if (countDownLatch.await(DEFAULT_TIMEOUT_SEC, TimeUnit.SECONDS)) { - return response.get(); - } + return result.get(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); - throw new SiftException("Interrupted while waiting for reply from Sift"); + result.cancel(true); + throw new InterruptedIOException("Interrupted while waiting for reply from Sift"); + } catch (ExecutionException e) { + throw new IOException(e); } - throw new SiftException("Timeout while waiting for reply from Sift"); } } From fa85ca70d86bf4908d11389e13948439e04384e2 Mon Sep 17 00:00:00 2001 From: Sasha Bogolii Date: Tue, 21 May 2024 17:07:06 +0300 Subject: [PATCH 3/6] API-7698: Added overloaded constructor with both baseUrl and okHttpClient --- src/main/java/com/siftscience/SiftClient.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/siftscience/SiftClient.java b/src/main/java/com/siftscience/SiftClient.java index f69a236..cc7e9f0 100644 --- a/src/main/java/com/siftscience/SiftClient.java +++ b/src/main/java/com/siftscience/SiftClient.java @@ -72,6 +72,11 @@ public SiftClient(String apiKey, String accountId, HttpUrl baseUrl) { this.baseUrl = baseUrl; } + public SiftClient(String apiKey, String accountId, HttpUrl baseUrl, OkHttpClient okHttpClient) { + this(apiKey, accountId, okHttpClient); + this.baseUrl = baseUrl; + } + public String getApiKey() { return apiKey; } From 279aab442b2836b5273cd542aced8d7d90e266e7 Mon Sep 17 00:00:00 2001 From: Sasha Bogolii Date: Wed, 22 May 2024 10:51:02 +0300 Subject: [PATCH 4/6] API-7698: Made enqueue requests optional --- .../com/siftscience/ApplyDecisionRequest.java | 8 ++-- .../siftscience/CreateMerchantRequest.java | 11 +++-- .../siftscience/DecisionStatusRequest.java | 12 +++--- .../java/com/siftscience/EventRequest.java | 4 +- .../com/siftscience/GetDecisionsRequest.java | 9 ++--- .../com/siftscience/GetMerchantRequest.java | 13 +++--- .../com/siftscience/GetMerchantsRequest.java | 13 +++--- src/main/java/com/siftscience/HttpClient.java | 31 ++++++++++++++ .../java/com/siftscience/LabelRequest.java | 9 ++--- .../java/com/siftscience/ScoreRequest.java | 5 +-- src/main/java/com/siftscience/SiftClient.java | 40 ++++++++++--------- .../com/siftscience/SiftMerchantRequest.java | 8 ++-- .../java/com/siftscience/SiftRequest.java | 25 ++++++++---- .../java/com/siftscience/UnlabelRequest.java | 4 +- .../siftscience/UpdateMerchantRequest.java | 4 +- .../com/siftscience/UserScoreRequest.java | 9 ++--- .../siftscience/VerificationCheckRequest.java | 15 ++++--- .../VerificationResendRequest.java | 15 ++++--- .../siftscience/VerificationSendRequest.java | 15 ++++--- .../siftscience/WorkflowStatusRequest.java | 14 ++++--- 20 files changed, 156 insertions(+), 108 deletions(-) create mode 100644 src/main/java/com/siftscience/HttpClient.java diff --git a/src/main/java/com/siftscience/ApplyDecisionRequest.java b/src/main/java/com/siftscience/ApplyDecisionRequest.java index df3c647..b6cfa2d 100644 --- a/src/main/java/com/siftscience/ApplyDecisionRequest.java +++ b/src/main/java/com/siftscience/ApplyDecisionRequest.java @@ -3,12 +3,14 @@ import java.io.IOException; import com.siftscience.model.ApplyDecisionFieldSet; -import okhttp3.*; +import okhttp3.Credentials; +import okhttp3.HttpUrl; +import okhttp3.Request; public class ApplyDecisionRequest extends SiftRequest{ - ApplyDecisionRequest(HttpUrl baseUrl, String accountId, OkHttpClient okClient, ApplyDecisionFieldSet fields) { - super(baseUrl, accountId, okClient, fields); + ApplyDecisionRequest(HttpUrl baseUrl, String accountId, HttpClient httpClient, ApplyDecisionFieldSet fields) { + super(baseUrl, accountId, httpClient, fields); } @Override diff --git a/src/main/java/com/siftscience/CreateMerchantRequest.java b/src/main/java/com/siftscience/CreateMerchantRequest.java index 05e8cfc..78525c0 100644 --- a/src/main/java/com/siftscience/CreateMerchantRequest.java +++ b/src/main/java/com/siftscience/CreateMerchantRequest.java @@ -1,18 +1,17 @@ package com.siftscience; +import java.io.IOException; + +import okhttp3.Credentials; import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; -import okhttp3.Credentials; - -import java.io.IOException; public class CreateMerchantRequest extends SiftMerchantRequest { - CreateMerchantRequest(HttpUrl baseUrl, String accountId, OkHttpClient okClient, FieldSet fields) { - super(baseUrl, accountId, okClient, fields); + CreateMerchantRequest(HttpUrl baseUrl, String accountId, HttpClient httpClient, FieldSet fields) { + super(baseUrl, accountId, httpClient, fields); } @Override diff --git a/src/main/java/com/siftscience/DecisionStatusRequest.java b/src/main/java/com/siftscience/DecisionStatusRequest.java index 130e111..daab859 100644 --- a/src/main/java/com/siftscience/DecisionStatusRequest.java +++ b/src/main/java/com/siftscience/DecisionStatusRequest.java @@ -1,16 +1,18 @@ package com.siftscience; -import com.siftscience.model.DecisionStatusFieldSet; -import okhttp3.*; - import java.io.IOException; import static com.siftscience.model.DecisionStatusFieldSet.ENTITY_CONTENT; import static com.siftscience.model.DecisionStatusFieldSet.ENTITY_SESSIONS; +import com.siftscience.model.DecisionStatusFieldSet; +import okhttp3.Credentials; +import okhttp3.HttpUrl; +import okhttp3.Request; +import okhttp3.Response; public class DecisionStatusRequest extends SiftRequest { - DecisionStatusRequest(HttpUrl baseUrl, String accountId, OkHttpClient okClient, DecisionStatusFieldSet fields) { - super(baseUrl, accountId, okClient, fields); + DecisionStatusRequest(HttpUrl baseUrl, String accountId, HttpClient httpClient, DecisionStatusFieldSet fields) { + super(baseUrl, accountId, httpClient, fields); } @Override diff --git a/src/main/java/com/siftscience/EventRequest.java b/src/main/java/com/siftscience/EventRequest.java index a18ac49..e94a746 100644 --- a/src/main/java/com/siftscience/EventRequest.java +++ b/src/main/java/com/siftscience/EventRequest.java @@ -22,8 +22,8 @@ public class EventRequest extends SiftRequest { private boolean returnScorePercentiles = false; private boolean returnWarnings = false; - EventRequest(HttpUrl baseUrl, String accountId, OkHttpClient okClient, FieldSet fields) { - super(baseUrl, accountId, okClient, fields); + EventRequest(HttpUrl baseUrl, String accountId, HttpClient client, FieldSet fields) { + super(baseUrl, accountId, client, fields); abuseTypes = null; } diff --git a/src/main/java/com/siftscience/GetDecisionsRequest.java b/src/main/java/com/siftscience/GetDecisionsRequest.java index 2fa9436..7b83a54 100644 --- a/src/main/java/com/siftscience/GetDecisionsRequest.java +++ b/src/main/java/com/siftscience/GetDecisionsRequest.java @@ -1,19 +1,18 @@ package com.siftscience; -import com.siftscience.model.GetDecisionFieldSet; - import java.io.IOException; + +import com.siftscience.model.GetDecisionFieldSet; import okhttp3.Credentials; import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; public class GetDecisionsRequest extends SiftRequest { - GetDecisionsRequest(HttpUrl baseUrl, String accountId, OkHttpClient okClient, FieldSet fields) { - super(baseUrl, accountId, okClient, fields); + GetDecisionsRequest(HttpUrl baseUrl, String accountId, HttpClient httpClient, FieldSet fields) { + super(baseUrl, accountId, httpClient, fields); } public enum Query { diff --git a/src/main/java/com/siftscience/GetMerchantRequest.java b/src/main/java/com/siftscience/GetMerchantRequest.java index c5cd708..e7d36b0 100644 --- a/src/main/java/com/siftscience/GetMerchantRequest.java +++ b/src/main/java/com/siftscience/GetMerchantRequest.java @@ -1,15 +1,18 @@ package com.siftscience; -import com.siftscience.model.GetMerchantFieldSet; -import okhttp3.*; - import java.io.IOException; +import com.siftscience.model.GetMerchantFieldSet; +import okhttp3.Credentials; +import okhttp3.HttpUrl; +import okhttp3.Request; +import okhttp3.Response; + public class GetMerchantRequest extends SiftMerchantRequest { - GetMerchantRequest(HttpUrl baseUrl, String accountId, OkHttpClient okClient, FieldSet fields) { - super(baseUrl, accountId, okClient, fields); + GetMerchantRequest(HttpUrl baseUrl, String accountId, HttpClient httpClient, FieldSet fields) { + super(baseUrl, accountId, httpClient, fields); } @Override diff --git a/src/main/java/com/siftscience/GetMerchantsRequest.java b/src/main/java/com/siftscience/GetMerchantsRequest.java index ac4ec76..1361f48 100644 --- a/src/main/java/com/siftscience/GetMerchantsRequest.java +++ b/src/main/java/com/siftscience/GetMerchantsRequest.java @@ -1,15 +1,18 @@ package com.siftscience; -import com.siftscience.model.GetMerchantsFieldSet; -import okhttp3.*; - import java.io.IOException; +import com.siftscience.model.GetMerchantsFieldSet; +import okhttp3.Credentials; +import okhttp3.HttpUrl; +import okhttp3.Request; +import okhttp3.Response; + public class GetMerchantsRequest extends SiftMerchantRequest { - GetMerchantsRequest(HttpUrl baseUrl, String accountId, OkHttpClient okClient, FieldSet fields) { - super(baseUrl, accountId, okClient, fields); + GetMerchantsRequest(HttpUrl baseUrl, String accountId, HttpClient httpClient, FieldSet fields) { + super(baseUrl, accountId, httpClient, fields); } private static String DEFAULT_BATCH_SIZE = "1000"; diff --git a/src/main/java/com/siftscience/HttpClient.java b/src/main/java/com/siftscience/HttpClient.java new file mode 100644 index 0000000..3bcdd9a --- /dev/null +++ b/src/main/java/com/siftscience/HttpClient.java @@ -0,0 +1,31 @@ +package com.siftscience; + +import java.io.IOException; + +import com.siftscience.utils.OkHttpUtils; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +public class HttpClient { + + private final OkHttpClient okClient; + private boolean enqueueRequests; + + public HttpClient(OkHttpClient okHttpClient) { + this.okClient = okHttpClient; + } + + public OkHttpClient getOkClient() { + return okClient; + } + + public Response execute(Request request) throws IOException { + return enqueueRequests ? OkHttpUtils.execute(request, okClient) : + okClient.newCall(request).execute(); + } + + public void enqueueRequests() { + this.enqueueRequests = true; + } +} diff --git a/src/main/java/com/siftscience/LabelRequest.java b/src/main/java/com/siftscience/LabelRequest.java index bc44e56..6a0a439 100644 --- a/src/main/java/com/siftscience/LabelRequest.java +++ b/src/main/java/com/siftscience/LabelRequest.java @@ -1,19 +1,18 @@ package com.siftscience; +import java.io.IOException; + import com.siftscience.model.LabelFieldSet; import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; import okhttp3.Response; -import java.io.IOException; - /** * LabelRequest is the request type for the Sift Labels API. * https://siftscience.com/developers/docs/curl/labels-api */ public class LabelRequest extends SiftRequest { - LabelRequest(HttpUrl baseUrl, String accountId, OkHttpClient okClient, LabelFieldSet fields) { - super(baseUrl, accountId, okClient, fields); + LabelRequest(HttpUrl baseUrl, String accountId, HttpClient httpClient, LabelFieldSet fields) { + super(baseUrl, accountId, httpClient, fields); } @Override diff --git a/src/main/java/com/siftscience/ScoreRequest.java b/src/main/java/com/siftscience/ScoreRequest.java index 89735c2..b499f7b 100644 --- a/src/main/java/com/siftscience/ScoreRequest.java +++ b/src/main/java/com/siftscience/ScoreRequest.java @@ -4,7 +4,6 @@ import com.siftscience.model.ScoreFieldSet; import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; @@ -13,8 +12,8 @@ * https://siftscience.com/developers/docs/curl/score-api */ public class ScoreRequest extends SiftRequest { - ScoreRequest(HttpUrl baseUrl, String accountId, OkHttpClient okClient, ScoreFieldSet fields) { - super(baseUrl, accountId, okClient, fields); + ScoreRequest(HttpUrl baseUrl, String accountId, HttpClient httpClient, ScoreFieldSet fields) { + super(baseUrl, accountId, httpClient, fields); } /** diff --git a/src/main/java/com/siftscience/SiftClient.java b/src/main/java/com/siftscience/SiftClient.java index cc7e9f0..5b3e471 100644 --- a/src/main/java/com/siftscience/SiftClient.java +++ b/src/main/java/com/siftscience/SiftClient.java @@ -48,7 +48,7 @@ public class SiftClient { private final String accountId; private final String apiKey; - private final OkHttpClient okClient; + private final HttpClient httpClient; private HttpUrl baseUrl = HttpUrl.parse("https://api.sift.com"); public SiftClient(String apiKey, String accountId) { @@ -58,7 +58,7 @@ public SiftClient(String apiKey, String accountId) { public SiftClient(String apiKey, String accountId, OkHttpClient okHttpClient) { this.apiKey = apiKey; this.accountId = accountId; - this.okClient = okHttpClient; + this.httpClient = new HttpClient(okHttpClient); } /** @@ -85,84 +85,88 @@ public String getAccountId() { return accountId; } + public void enqueueRequests() { + httpClient.enqueueRequests(); + } + public EventRequest buildRequest(FieldSet fields) { setupApiKey(fields); - return new EventRequest(baseUrl, getAccountId(), okClient, fields); + return new EventRequest(baseUrl, getAccountId(), httpClient, fields); } public ApplyDecisionRequest buildRequest(ApplyDecisionFieldSet fields) { setupApiKey(fields); - return new ApplyDecisionRequest(baseUrl, getAccountId(), okClient, fields); + return new ApplyDecisionRequest(baseUrl, getAccountId(), httpClient, fields); } public GetDecisionsRequest buildRequest(GetDecisionFieldSet fields) { setupApiKey(fields); - return new GetDecisionsRequest(baseUrl, getAccountId(), okClient, fields); + return new GetDecisionsRequest(baseUrl, getAccountId(), httpClient, fields); } public DecisionStatusRequest buildRequest(DecisionStatusFieldSet fields) { setupApiKey(fields); - return new DecisionStatusRequest(baseUrl, getAccountId(), okClient, fields); + return new DecisionStatusRequest(baseUrl, getAccountId(), httpClient, fields); } public LabelRequest buildRequest(LabelFieldSet fields) { setupApiKey(fields); - return new LabelRequest(baseUrl, getAccountId(), okClient, fields); + return new LabelRequest(baseUrl, getAccountId(), httpClient, fields); } public UnlabelRequest buildRequest(UnlabelFieldSet fields) { setupApiKey(fields); - return new UnlabelRequest(baseUrl, getAccountId(), okClient, fields); + return new UnlabelRequest(baseUrl, getAccountId(), httpClient, fields); } public ScoreRequest buildRequest(ScoreFieldSet fields) { setupApiKey(fields); - return new ScoreRequest(baseUrl, getAccountId(), okClient, fields); + return new ScoreRequest(baseUrl, getAccountId(), httpClient, fields); } public UserScoreRequest buildRequest(UserScoreFieldSet fields) { setupApiKey(fields); - return new UserScoreRequest(baseUrl, getAccountId(), okClient, fields); + return new UserScoreRequest(baseUrl, getAccountId(), httpClient, fields); } public WorkflowStatusRequest buildRequest(WorkflowStatusFieldSet fields) { setupApiKey(fields); - return new WorkflowStatusRequest(baseUrl, getAccountId(), okClient, fields); + return new WorkflowStatusRequest(baseUrl, getAccountId(), httpClient, fields); } public GetMerchantsRequest buildRequest(GetMerchantsFieldSet fields) { setupApiKey(fields); - return new GetMerchantsRequest(baseUrl, getAccountId(), okClient, fields); + return new GetMerchantsRequest(baseUrl, getAccountId(), httpClient, fields); } public GetMerchantRequest buildRequest(GetMerchantFieldSet fields) { setupApiKey(fields); - return new GetMerchantRequest(baseUrl, getAccountId(), okClient, fields); + return new GetMerchantRequest(baseUrl, getAccountId(), httpClient, fields); } public CreateMerchantRequest buildRequest(CreateMerchantFieldSet fields) { setupApiKey(fields); - return new CreateMerchantRequest(baseUrl, getAccountId(), okClient, fields); + return new CreateMerchantRequest(baseUrl, getAccountId(), httpClient, fields); } public UpdateMerchantRequest buildRequest(UpdateMerchantFieldSet fields, String merchantId) { setupApiKey(fields); - return new UpdateMerchantRequest(baseUrl, getAccountId(), okClient, fields, merchantId); + return new UpdateMerchantRequest(baseUrl, getAccountId(), httpClient, fields, merchantId); } public VerificationSendRequest buildRequest(VerificationSendFieldSet fields) { setupApiKey(fields); - return new VerificationSendRequest(baseUrl, getAccountId(), okClient, fields); + return new VerificationSendRequest(baseUrl, getAccountId(), httpClient, fields); } public VerificationResendRequest buildRequest(VerificationResendFieldSet fields) { setupApiKey(fields); - return new VerificationResendRequest(baseUrl, getAccountId(), okClient, fields); + return new VerificationResendRequest(baseUrl, getAccountId(), httpClient, fields); } public VerificationCheckRequest buildRequest(VerificationCheckFieldSet fields) { setupApiKey(fields); - return new VerificationCheckRequest(baseUrl, getAccountId(), okClient, fields); + return new VerificationCheckRequest(baseUrl, getAccountId(), httpClient, fields); } private void setupApiKey(FieldSet fields) { diff --git a/src/main/java/com/siftscience/SiftMerchantRequest.java b/src/main/java/com/siftscience/SiftMerchantRequest.java index c89597b..7183486 100644 --- a/src/main/java/com/siftscience/SiftMerchantRequest.java +++ b/src/main/java/com/siftscience/SiftMerchantRequest.java @@ -17,7 +17,7 @@ public abstract class SiftMerchantRequest { private final String accountId; FieldSet fieldSet; - private OkHttpClient okClient; + private HttpClient httpClient; private HttpUrl baseUrl; protected abstract HttpUrl path(HttpUrl baseUrl); @@ -26,10 +26,10 @@ public HttpUrl url() { return path(baseUrl); } - SiftMerchantRequest(HttpUrl baseUrl, String accountId, OkHttpClient okClient, FieldSet fields) { + SiftMerchantRequest(HttpUrl baseUrl, String accountId, HttpClient httpClient, FieldSet fields) { this.baseUrl = baseUrl; this.accountId = accountId; - this.okClient = okClient; + this.httpClient = httpClient; this.fieldSet = fields; } @@ -50,7 +50,7 @@ public T send() throws IOException { new Request.Builder().addHeader("User-Agent", USER_AGENT_HEADER).url(this.url()); modifyRequestBuilder(okRequestBuilder); Request request = okRequestBuilder.build(); - T response = buildResponse(OkHttpUtils.execute(request, okClient), fieldSet); + T response = buildResponse(httpClient.execute(request), fieldSet); if (!response.isOk()) { throw new MerchantAPIException(response.getApiErrorMessage()); diff --git a/src/main/java/com/siftscience/SiftRequest.java b/src/main/java/com/siftscience/SiftRequest.java index 2d064db..a3cc05e 100644 --- a/src/main/java/com/siftscience/SiftRequest.java +++ b/src/main/java/com/siftscience/SiftRequest.java @@ -1,12 +1,21 @@ package com.siftscience; -import com.siftscience.exception.*; -import com.siftscience.utils.OkHttpUtils; -import okhttp3.*; - import java.io.IOException; import static com.siftscience.Constants.USER_AGENT_HEADER; +import com.siftscience.exception.InvalidApiKeyException; +import com.siftscience.exception.InvalidFieldException; +import com.siftscience.exception.InvalidRequestException; +import com.siftscience.exception.MissingFieldException; +import com.siftscience.exception.RateLimitException; +import com.siftscience.exception.ServerException; +import com.siftscience.exception.SiftException; +import com.siftscience.utils.OkHttpUtils; +import okhttp3.HttpUrl; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; /** * SiftRequest is the base class for all Sift API requests. It implements the `send` method which @@ -15,7 +24,7 @@ public abstract class SiftRequest { private final String accountId; FieldSet fieldSet; - private OkHttpClient okClient; + private HttpClient httpClient; private HttpUrl baseUrl; protected abstract HttpUrl path(HttpUrl baseUrl); @@ -24,10 +33,10 @@ public HttpUrl url() { return path(baseUrl); } - SiftRequest(HttpUrl baseUrl, String accountId, OkHttpClient okClient, FieldSet fields) { + SiftRequest(HttpUrl baseUrl, String accountId, HttpClient httpClient, FieldSet fields) { this.baseUrl = baseUrl; this.accountId = accountId; - this.okClient = okClient; + this.httpClient = httpClient; this.fieldSet = fields; } @@ -47,7 +56,7 @@ public T send() throws IOException { Request.Builder okRequestBuilder = new Request.Builder().addHeader("User-Agent", USER_AGENT_HEADER).url(this.url()); modifyRequestBuilder(okRequestBuilder); Request request = okRequestBuilder.build(); - T response = buildResponse(OkHttpUtils.execute(request, okClient), fieldSet); + T response = buildResponse(httpClient.execute(request), fieldSet); // If not successful but no exception happened yet, dig deeper into the response so we // can manually throw an appropriate exception. diff --git a/src/main/java/com/siftscience/UnlabelRequest.java b/src/main/java/com/siftscience/UnlabelRequest.java index bf273ce..2939bc8 100644 --- a/src/main/java/com/siftscience/UnlabelRequest.java +++ b/src/main/java/com/siftscience/UnlabelRequest.java @@ -10,9 +10,9 @@ * https://siftscience.com/developers/docs/curl/labels-api/unlabel-user */ public class UnlabelRequest extends SiftRequest { - UnlabelRequest(HttpUrl baseUrl, String accountId, OkHttpClient okClient, + UnlabelRequest(HttpUrl baseUrl, String accountId, HttpClient httpClient, UnlabelFieldSet fields) { - super(baseUrl, accountId, okClient, fields); + super(baseUrl, accountId, httpClient, fields); } /** diff --git a/src/main/java/com/siftscience/UpdateMerchantRequest.java b/src/main/java/com/siftscience/UpdateMerchantRequest.java index dd1803b..24a7c83 100644 --- a/src/main/java/com/siftscience/UpdateMerchantRequest.java +++ b/src/main/java/com/siftscience/UpdateMerchantRequest.java @@ -16,8 +16,8 @@ public class UpdateMerchantRequest extends SiftMerchantRequest { - UserScoreRequest(HttpUrl baseUrl, String accountId, OkHttpClient okClient, + UserScoreRequest(HttpUrl baseUrl, String accountId, HttpClient httpClient, UserScoreFieldSet fields) { - super(baseUrl, accountId, okClient, fields); + super(baseUrl, accountId, httpClient, fields); } /** diff --git a/src/main/java/com/siftscience/VerificationCheckRequest.java b/src/main/java/com/siftscience/VerificationCheckRequest.java index b2b296d..fa021bb 100644 --- a/src/main/java/com/siftscience/VerificationCheckRequest.java +++ b/src/main/java/com/siftscience/VerificationCheckRequest.java @@ -1,15 +1,14 @@ package com.siftscience; +import java.io.IOException; + import com.siftscience.model.VerificationCheckFieldSet; -import okhttp3.OkHttpClient; -import okhttp3.HttpUrl; -import okhttp3.Response; -import okhttp3.Request; import okhttp3.Credentials; +import okhttp3.HttpUrl; import okhttp3.MediaType; +import okhttp3.Request; import okhttp3.RequestBody; - -import java.io.IOException; +import okhttp3.Response; /** @@ -18,8 +17,8 @@ */ public class VerificationCheckRequest extends SiftRequest { - VerificationCheckRequest(HttpUrl baseUrl, String accountId, OkHttpClient okClient, VerificationCheckFieldSet fields) { - super(baseUrl, accountId, okClient, fields); + VerificationCheckRequest(HttpUrl baseUrl, String accountId, HttpClient httpClient, VerificationCheckFieldSet fields) { + super(baseUrl, accountId, httpClient, fields); } @Override diff --git a/src/main/java/com/siftscience/VerificationResendRequest.java b/src/main/java/com/siftscience/VerificationResendRequest.java index 2b0ad81..074c2c6 100644 --- a/src/main/java/com/siftscience/VerificationResendRequest.java +++ b/src/main/java/com/siftscience/VerificationResendRequest.java @@ -1,15 +1,14 @@ package com.siftscience; +import java.io.IOException; + import com.siftscience.model.VerificationResendFieldSet; -import okhttp3.OkHttpClient; -import okhttp3.HttpUrl; -import okhttp3.Response; -import okhttp3.Request; import okhttp3.Credentials; +import okhttp3.HttpUrl; import okhttp3.MediaType; +import okhttp3.Request; import okhttp3.RequestBody; - -import java.io.IOException; +import okhttp3.Response; /** * The resend call generates a new OTP and sends it to the original recipient with the same settings. @@ -17,8 +16,8 @@ * */ public class VerificationResendRequest extends SiftRequest { - VerificationResendRequest(HttpUrl baseUrl, String accountId, OkHttpClient okClient, VerificationResendFieldSet fields) { - super(baseUrl, accountId, okClient, fields); + VerificationResendRequest(HttpUrl baseUrl, String accountId, HttpClient httpClient, VerificationResendFieldSet fields) { + super(baseUrl, accountId, httpClient, fields); } @Override diff --git a/src/main/java/com/siftscience/VerificationSendRequest.java b/src/main/java/com/siftscience/VerificationSendRequest.java index 89bc063..ec81afc 100644 --- a/src/main/java/com/siftscience/VerificationSendRequest.java +++ b/src/main/java/com/siftscience/VerificationSendRequest.java @@ -1,15 +1,14 @@ package com.siftscience; +import java.io.IOException; + import com.siftscience.model.VerificationSendFieldSet; -import okhttp3.OkHttpClient; -import okhttp3.HttpUrl; -import okhttp3.Response; -import okhttp3.Request; import okhttp3.Credentials; +import okhttp3.HttpUrl; import okhttp3.MediaType; +import okhttp3.Request; import okhttp3.RequestBody; - -import java.io.IOException; +import okhttp3.Response; /** *The send call triggers the generation of an OTP code that is stored by Sift @@ -18,8 +17,8 @@ * */ public class VerificationSendRequest extends SiftRequest { - VerificationSendRequest(HttpUrl baseUrl, String accountId, OkHttpClient okClient, VerificationSendFieldSet fields) { - super(baseUrl, accountId, okClient, fields); + VerificationSendRequest(HttpUrl baseUrl, String accountId, HttpClient httpClient, VerificationSendFieldSet fields) { + super(baseUrl, accountId, httpClient, fields); } @Override diff --git a/src/main/java/com/siftscience/WorkflowStatusRequest.java b/src/main/java/com/siftscience/WorkflowStatusRequest.java index 2b921e0..a747078 100644 --- a/src/main/java/com/siftscience/WorkflowStatusRequest.java +++ b/src/main/java/com/siftscience/WorkflowStatusRequest.java @@ -1,14 +1,16 @@ package com.siftscience; -import com.siftscience.model.WorkflowStatus; -import com.siftscience.model.WorkflowStatusFieldSet; -import okhttp3.*; - import java.io.IOException; +import com.siftscience.model.WorkflowStatusFieldSet; +import okhttp3.Credentials; +import okhttp3.HttpUrl; +import okhttp3.Request; +import okhttp3.Response; + public class WorkflowStatusRequest extends SiftRequest { - WorkflowStatusRequest(HttpUrl baseUrl, String accountId, OkHttpClient okClient, FieldSet fields) { - super(baseUrl, accountId, okClient, fields); + WorkflowStatusRequest(HttpUrl baseUrl, String accountId, HttpClient httpClient, FieldSet fields) { + super(baseUrl, accountId, httpClient, fields); } @Override From b6e2264fffe66c896f68d5254a5b99322bc70f4a Mon Sep 17 00:00:00 2001 From: Sasha Bogolii Date: Fri, 24 May 2024 12:20:05 +0300 Subject: [PATCH 5/6] API-7698: Don't interrupt --- src/main/java/com/siftscience/utils/OkHttpUtils.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/siftscience/utils/OkHttpUtils.java b/src/main/java/com/siftscience/utils/OkHttpUtils.java index f7d36ee..7d9fd84 100644 --- a/src/main/java/com/siftscience/utils/OkHttpUtils.java +++ b/src/main/java/com/siftscience/utils/OkHttpUtils.java @@ -22,7 +22,8 @@ private OkHttpUtils() { * which causes java.net.SocketTimeoutException from HTTP/2 connection to leave dead okhttp * clients in pool. * This utility method is used as a - * workaround + * + * workaround * to enqueue and sync wait for response * * @param request - request to send @@ -45,7 +46,9 @@ public void onResponse(@NotNull Call call, @NotNull Response httpResponse) { try { return result.get(); } catch (InterruptedException e) { - Thread.currentThread().interrupt(); + // Intentionally don't interrupt, as it causes okHHtp fail as described + // in the link in javadoc + // Thread.currentThread().interrupt(); result.cancel(true); throw new InterruptedIOException("Interrupted while waiting for reply from Sift"); } catch (ExecutionException e) { From e21e0f3f0da11b427d2f1289c67b6d3518f1e361 Mon Sep 17 00:00:00 2001 From: Sasha Bogolii Date: Tue, 28 May 2024 12:00:51 +0300 Subject: [PATCH 6/6] API-7698: Added test --- .../java/com/siftscience/SiftRequestTest.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/test/java/com/siftscience/SiftRequestTest.java b/src/test/java/com/siftscience/SiftRequestTest.java index 1c6c985..f6ef2cb 100644 --- a/src/test/java/com/siftscience/SiftRequestTest.java +++ b/src/test/java/com/siftscience/SiftRequestTest.java @@ -40,4 +40,31 @@ public void testUserAgentHeader() throws Exception { Assert.assertEquals("SiftScience/v205 sift-java/3.14.2", recordedRequest.getHeader("User-Agent")); } + @Test + public void testEnqueueRequests() throws Exception { + MockWebServer server = new MockWebServer(); + MockResponse response = new MockResponse(); + response.setResponseCode(HTTP_OK); + + server.enqueue(response); + server.start(); + + // Create a new client and link it to the mock server. + SiftClient client = new SiftClient("YOUR_API_KEY", "YOUR_ACCOUNT_ID", + new OkHttpClient.Builder() + .addInterceptor(OkHttpUtils.urlRewritingInterceptor(server)) + .build()); + client.enqueueRequests(); + + // Build and execute the request against the mock server. + ApplyDecisionRequest request = client.buildRequest( + new ApplyDecisionFieldSet() + .setUserId("a_user_id") + .setTime(System.currentTimeMillis())); + + ApplyDecisionResponse receivedResponse = request.send(); + + // verify + Assert.assertNotNull(receivedResponse); + } }