diff --git a/.gitignore b/.gitignore index d40a9d7..6ced83a 100644 --- a/.gitignore +++ b/.gitignore @@ -29,9 +29,10 @@ proguard/ .gradletasknamecache .gradle .gradle/ +gradle.properties + build/ bin/ -gradle.properties /.vs/VSWorkspaceState.json /.vs/socketlabs-java/v17/TestStore/0/testlog.manifest /.vs/socketlabs-java/v17/TestStore/0/000.testlog diff --git a/examples/build.gradle b/examples/build.gradle index fcf2b44..fd674c9 100644 --- a/examples/build.gradle +++ b/examples/build.gradle @@ -8,13 +8,17 @@ version '1.0-SNAPSHOT' sourceCompatibility = 1.8 repositories { - mavenLocal() mavenCentral() + maven { + url = uri("https://central.sonatype.com/repository/maven-snapshots/") + } + mavenLocal() } dependencies { - testCompile group: 'junit', name: 'junit', version: '4.9.2' compile 'com.fasterxml.jackson.core:jackson-core:2.14.0' compile 'com.fasterxml.jackson.core:jackson-databind:2.14.0' - compile group: 'com.socketlabs', name: 'injectionApi', version: '1.4.2' + compile 'org.apache.httpcomponents:httpclient:4.5.14' + compile 'org.apache.httpcomponents:httpasyncclient:4.1.5' + compile group: 'com.socketlabs', name: 'injectionApi', version: '2.0.1-SNAPSHOT' } diff --git a/examples/gradle/wrapper/gradle-wrapper.jar b/examples/gradle/wrapper/gradle-wrapper.jar index 1948b90..457aad0 100644 Binary files a/examples/gradle/wrapper/gradle-wrapper.jar and b/examples/gradle/wrapper/gradle-wrapper.jar differ diff --git a/examples/gradle/wrapper/gradle-wrapper.properties b/examples/gradle/wrapper/gradle-wrapper.properties index a833f72..75b8c7c 100644 --- a/examples/gradle/wrapper/gradle-wrapper.properties +++ b/examples/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Thu Jun 18 12:46:49 EDT 2020 -distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-all.zip distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.0-bin.zip zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/examples/gradlew b/examples/gradlew index cccdd3d..af6708f 100644 --- a/examples/gradlew +++ b/examples/gradlew @@ -28,7 +28,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" diff --git a/examples/gradlew.bat b/examples/gradlew.bat index f955316..6d57edc 100644 --- a/examples/gradlew.bat +++ b/examples/gradlew.bat @@ -14,7 +14,7 @@ set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome diff --git a/examples/src/main/java/examples/Main.java b/examples/src/main/java/examples/Main.java index 4de3a66..d33b1a0 100644 --- a/examples/src/main/java/examples/Main.java +++ b/examples/src/main/java/examples/Main.java @@ -59,22 +59,24 @@ private static void DisplayTheMenu() { System.out.println(" 10: Basic Async With Retry"); System.out.println(" 11: Basic Send With Retry "); System.out.println(" 12: Basic Send Complex Example "); + System.out.println(" 13: Basic Send With HttpClient "); + System.out.println(" 14: Basic Send With HttpAsyncClient "); System.out.println(); System.out.println(" Validation Error Handling Examples: "); - System.out.println(" 13: Basic Send With Invalid Attachment"); - System.out.println(" 14: Basic Send With Invalid From "); - System.out.println(" 15: Basic Send With Invalid Recipients "); + System.out.println(" 15: Basic Send With Invalid Attachment"); + System.out.println(" 16: Basic Send With Invalid From "); + System.out.println(" 17: Basic Send With Invalid Recipients "); System.out.println(); System.out.println(" Bulk Send Examples: "); - System.out.println(" 16: Bulk Send "); - System.out.println(" 17: Bulk Send With MergeData "); - System.out.println(" 18: Bulk Send With ASCII Charset And Merge Data "); - System.out.println(" 19: Bulk Send From DataSource With Merge Data "); - System.out.println(" 20: Bulk Send Complex Example "); + System.out.println(" 18: Bulk Send "); + System.out.println(" 19: Bulk Send With MergeData "); + System.out.println(" 20: Bulk Send With ASCII Charset And Merge Data "); + System.out.println(" 21: Bulk Send From DataSource With Merge Data "); + System.out.println(" 22: Bulk Send Complex Example "); System.out.println(); System.out.println(" AMP Html Examples: "); - System.out.println(" 21: Basic Send With Amp Body Example "); - System.out.println(" 22: Bulk Send With Amp Body Example "); + System.out.println(" 23: Basic Send With Amp Body Example "); + System.out.println(" 24: Bulk Send With Amp Body Example "); System.out.println(); @@ -104,17 +106,19 @@ private static String GetExampleName(String selection) { case 10: return "examples.basic.BasicAsyncWithRetry"; case 11: return "examples.basic.BasicSendWithRetry"; case 12: return "examples.basic.BasicSendComplexExample"; - case 13: return "examples.basic.invalid.BasicSendWithInvalidAttachment"; - case 14: return "examples.basic.invalid.BasicSendWithInvalidFrom"; - case 15: return "examples.basic.invalid.BasicSendWithInvalidRecipients"; - - case 16: return "examples.bulk.BulkSend"; - case 17: return "examples.bulk.BulkSendWithMergeData"; - case 18: return "examples.bulk.BulkSendWithASCIICharsetMergeData"; - case 19: return "examples.bulk.BulkSendFromDataSourceWithMerge"; - case 20: return "examples.bulk.BulkSendComplexExample"; - case 21: return "examples.basic.BasicSendWithAmpBodyExample"; - case 22: return "examples.bulk.BulkSendWithAmpBodyExample"; + case 13: return "examples.basic.BasicSendWithHttpClient"; + case 14: return "examples.basic.BasicSendWithHttpAsyncClient"; + case 15: return "examples.basic.invalid.BasicSendWithInvalidAttachment"; + case 16: return "examples.basic.invalid.BasicSendWithInvalidFrom"; + case 17: return "examples.basic.invalid.BasicSendWithInvalidRecipients"; + + case 18: return "examples.bulk.BulkSend"; + case 19: return "examples.bulk.BulkSendWithMergeData"; + case 20: return "examples.bulk.BulkSendWithASCIICharsetMergeData"; + case 21: return "examples.bulk.BulkSendFromDataSourceWithMerge"; + case 22: return "examples.bulk.BulkSendComplexExample"; + case 23: return "examples.basic.BasicSendWithAmpBodyExample"; + case 24: return "examples.bulk.BulkSendWithAmpBodyExample"; default: System.out.println("Invalid Input (Out of Range)"); return null; diff --git a/examples/src/main/java/examples/basic/BasicAsync.java b/examples/src/main/java/examples/basic/BasicAsync.java index 7b3fb6c..32d1dd9 100644 --- a/examples/src/main/java/examples/basic/BasicAsync.java +++ b/examples/src/main/java/examples/basic/BasicAsync.java @@ -8,7 +8,6 @@ import com.socketLabs.injectionApi.message.BasicMessage; import com.socketLabs.injectionApi.message.EmailAddress; import examples.*; -import okhttp3.Call; import java.io.IOException; diff --git a/examples/src/main/java/examples/basic/BasicSendWithHttpAsyncClient.java b/examples/src/main/java/examples/basic/BasicSendWithHttpAsyncClient.java new file mode 100644 index 0000000..eee7859 --- /dev/null +++ b/examples/src/main/java/examples/basic/BasicSendWithHttpAsyncClient.java @@ -0,0 +1,84 @@ +package examples.basic; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.socketLabs.injectionApi.SendResponse; +import com.socketLabs.injectionApi.SocketLabsClient; +import com.socketLabs.injectionApi.core.SendAsyncCallback; +import com.socketLabs.injectionApi.message.BasicMessage; +import com.socketLabs.injectionApi.message.EmailAddress; +import examples.*; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; +import org.apache.http.impl.nio.client.HttpAsyncClients; +import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager; +import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor; +import org.apache.http.nio.reactor.ConnectingIOReactor; + +import java.io.IOException; + +public class BasicSendWithHttpAsyncClient implements Example { + + @Override + public SendResponse RunExample() throws Exception { + + BasicMessage message = new BasicMessage(); + + message.setSubject("Sending A Test Message (Basic Send Async)"); + message.setHtmlBody("

Sending A Test Message

This is the Html Body of my message.

"); + message.setPlainTextBody("This is the Plain Text Body of my message."); + + message.setFrom(new EmailAddress("from@example.com")); + message.addToEmailAddress("recipient1@example.com"); + + // create the HttpClient + final ConnectingIOReactor ioReactor = new DefaultConnectingIOReactor(); + PoolingNHttpClientConnectionManager cm = new PoolingNHttpClientConnectionManager(ioReactor); + cm.setMaxTotal(200); + cm.setDefaultMaxPerRoute(20); + + RequestConfig requestConfig =RequestConfig.custom() + .setConnectTimeout(5000) + .setConnectionRequestTimeout(5000) + .setSocketTimeout(5000) + .build(); + + CloseableHttpAsyncClient httpClient = HttpAsyncClients.custom() + .setConnectionManager(cm) + .setDefaultRequestConfig(requestConfig) + .build(); + + // create the client + SocketLabsClient client = new SocketLabsClient(ExampleConfig.ServerId, ExampleConfig.ApiKey); + + // send the message + client.sendAsync(message, httpClient, new SendAsyncCallback() { + + @Override + public void onError(Exception ex) { + // Handle Exception here + ex.printStackTrace(); + return; + } + + @Override + public void onResponse(SendResponse response) throws IOException { + // Handle SendResponse here + + ObjectMapper mapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT); + + System.out.println("Response body : "); + System.out.println(mapper.writeValueAsString(response)); + System.out.println(); + System.out.println(); + System.out.println("Enter a number (or QUIT to exit):"); + + return; + + } + }); + + System.out.println("Waiting for response..."); + return null; + } +} diff --git a/examples/src/main/java/examples/basic/BasicSendWithHttpClient.java b/examples/src/main/java/examples/basic/BasicSendWithHttpClient.java new file mode 100644 index 0000000..7f7c26e --- /dev/null +++ b/examples/src/main/java/examples/basic/BasicSendWithHttpClient.java @@ -0,0 +1,53 @@ +package examples.basic; + +import com.socketLabs.injectionApi.SendResponse; +import com.socketLabs.injectionApi.SocketLabsClient; +import com.socketLabs.injectionApi.message.BasicMessage; +import com.socketLabs.injectionApi.message.EmailAddress; +import examples.*; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; + + +public class BasicSendWithHttpClient implements Example { + + public SendResponse RunExample () throws Exception { + + BasicMessage message = new BasicMessage(); + + message.setSubject("Sending An Email Through A Proxy"); + message.setHtmlBody("

Sending An Email Through A Proxy

This is the Html Body of my message.

"); + message.setPlainTextBody("This is the Plain Text Body of my message."); + + message.setFrom(new EmailAddress("from@example.com")); + message.addToEmailAddress("recipient1@example.com"); + + // create the HttpClient + PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); + cm.setMaxTotal(200); + cm.setDefaultMaxPerRoute(20); + cm.setValidateAfterInactivity(10000); + + RequestConfig requestConfig =RequestConfig.custom() + .setConnectTimeout(5000) + .setConnectionRequestTimeout(5000) + .setSocketTimeout(5000) + .build(); + + CloseableHttpClient httpClient = HttpClients.custom() + .setConnectionManager(cm) + .setDefaultRequestConfig(requestConfig) + .build(); + + // create the client + SocketLabsClient client = new SocketLabsClient(ExampleConfig.ServerId, ExampleConfig.ApiKey); + + // send the message + SendResponse response = client.send(message, httpClient); + + return response; + + } +} diff --git a/injectionApi/build.gradle b/injectionApi/build.gradle index 737b858..ae6a95a 100644 --- a/injectionApi/build.gradle +++ b/injectionApi/build.gradle @@ -4,40 +4,53 @@ plugins { id 'maven-publish' id 'signing' } + +def baseTitle ="SocketLabs Java" def baseGroupId = "com.socketlabs" -def baseArtifactId = 'injectionApi' -def computeVersion() { - def baseVersion = "1.4.4" +def baseArtifactId = "injectionApi" + +static def computeVersion() { + def baseVersion = "2.0.1" def release = true if (release) return "${baseVersion}" else return "${baseVersion}-SNAPSHOT" } + group "${baseGroupId}" version = computeVersion() + sourceCompatibility = 1.8 +targetCompatibility = 1.8 + repositories { mavenCentral() mavenLocal() } + compileJava { sourceCompatibility = '1.8' targetCompatibility = '1.8' } + dependencies { compile 'com.fasterxml.jackson.core:jackson-core:2.14.0' compile 'com.fasterxml.jackson.core:jackson-databind:2.14.0' compile group: 'com.google.guava', name: 'guava', version: '32.1.3-jre' - compile 'com.squareup.okhttp3:okhttp:4.10.0' - + compile 'org.apache.httpcomponents:httpclient:4.5.14' + compile 'org.apache.httpcomponents:httpasyncclient:4.1.5' } + jar { manifest { - attributes 'Implementation-Title': 'SocketLabs Java', + attributes( + 'Implementation-Title': baseTitle, 'Implementation-Version': version + ) } } + signing { required { gradle.taskGraph.hasTask("uploadArchives") } sign configurations.archives @@ -59,19 +72,21 @@ artifacts { archives sourceJar archives packageJavadoc } + +def mavenReleaseUrl = "file://projects/build/repo/release" +def mavenSnapshotUrl = "file://projects/build/repo/snapshot" + +// def mavenReleaseUrl = "https://ossrh-staging-api.central.sonatype.com/service/local/" +// def mavenSnapshotUrl = "https://central.sonatype.com/repository/maven-snapshots/" + uploadArchives { repositories { mavenDeployer { + beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } - - repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { - authentication(userName: sonatypeUsername, password: sonatypePassword) - } - snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots") { - authentication(userName: sonatypeUsername, password: sonatypePassword) - } + repository(url: "file:///projects/build/repo/release") pom.project { groupId "${baseGroupId}" @@ -81,6 +96,7 @@ uploadArchives { packaging 'jar' description 'SocketLabs Email Delivery Java library' url 'https://github.com/socketlabs/socketlabs-java/' + organization { name 'com.socketlabs' url 'https://github.com/socketlabs' diff --git a/injectionApi/gradle/wrapper/gradle-wrapper.properties b/injectionApi/gradle/wrapper/gradle-wrapper.properties index c369bdf..85b4545 100644 --- a/injectionApi/gradle/wrapper/gradle-wrapper.properties +++ b/injectionApi/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Oct 30 12:53:58 EDT 2018 +#Mon Jun 23 10:40:41 EDT 2025 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.0-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-all.zip diff --git a/injectionApi/pom.xml b/injectionApi/pom.xml index a0fc34b..a6d4754 100644 --- a/injectionApi/pom.xml +++ b/injectionApi/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.socketlabs injectionApi - 1.4.2 + 2.0.1 socketlabs-java SocketLabs Email Delivery Java library https://github.com/socketlabs/socketlabs-java/ @@ -23,7 +23,7 @@ david-schrenker David Schrenker david.schrenker@socketlabs.com - org.apache.maven.model.Organization@f125de5 + org.apache.maven.model.Organization@6817d1b6 Developer @@ -31,7 +31,7 @@ rbrazuk Ross Brazuk - org.apache.maven.model.Organization@19eaf41b + org.apache.maven.model.Organization@1d14f04e Developer @@ -39,7 +39,7 @@ mike.boshuyzen Mike Boshuyzen - org.apache.maven.model.Organization@6c023990 + org.apache.maven.model.Organization@2ef140cc Developer @@ -48,7 +48,7 @@ Ryan Lydzinski - org.apache.maven.model.Organization@399b8af0 + org.apache.maven.model.Organization@3b0ef3f7 Intern @@ -79,13 +79,19 @@ com.google.guava guava - 31.1-jre + 32.1.3-jre compile - com.squareup.okhttp3 - okhttp - 4.10.0 + org.apache.httpcomponents + httpclient + 4.5.14 + compile + + + org.apache.httpcomponents + httpasyncclient + 4.1.5 compile diff --git a/injectionApi/src/main/java/com/socketLabs/injectionApi/SocketLabsClient.java b/injectionApi/src/main/java/com/socketLabs/injectionApi/SocketLabsClient.java index ade1864..f7038ed 100644 --- a/injectionApi/src/main/java/com/socketLabs/injectionApi/SocketLabsClient.java +++ b/injectionApi/src/main/java/com/socketLabs/injectionApi/SocketLabsClient.java @@ -1,23 +1,45 @@ package com.socketLabs.injectionApi; +import com.google.common.collect.Lists; import com.socketLabs.injectionApi.core.*; import com.socketLabs.injectionApi.core.serialization.InjectionRequestFactory; import com.socketLabs.injectionApi.core.serialization.InjectionResponseParser; import com.socketLabs.injectionApi.message.*; import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.InetSocketAddress; import java.net.Proxy; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Response; +import java.util.List; + +import org.apache.http.Header; +import org.apache.http.HttpHeaders; +import org.apache.http.HttpHost; +import org.apache.http.HttpResponse; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.concurrent.FutureCallback; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; +import org.apache.http.impl.nio.client.HttpAsyncClients; +import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager; +import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor; +import org.apache.http.message.BasicHeader; +import org.apache.http.nio.reactor.ConnectingIOReactor; + /** * SocketLabsClient is a wrapper for the SocketLabs Injection API that makes it easy to send messages and parse responses. */ public class SocketLabsClient implements SocketLabsClientAPI { - private int serverId; - private String apiKey; + private final int serverId; + private final String apiKey; + private boolean useBearerAuth = false; private String endPointUrl = "https://inject.socketlabs.com/api/v1/email"; private Proxy proxy; private int requestTimeout = 100; @@ -43,8 +65,19 @@ public void setEndPointUrl(String value) { */ public void setNumberOfRetries(int value) { this.numberOfRetries = value; } - private final String VERSION = "1.0.0"; - private final String userAgent = String.format("SocketLabs-java/%s(%s)", VERSION, Package.getPackage("java.util").getImplementationVersion()); + private final String VERSION = "2.0.1"; + private final String JAVA_LANG_VERSION = Package.getPackage("java.lang").getImplementationVersion(); + private final String JAVA_UTIL_VERSION = Package.getPackage("java.util").getImplementationVersion(); + private final String JAVA_VERSION = (JAVA_UTIL_VERSION != null) ?JAVA_UTIL_VERSION : JAVA_LANG_VERSION; + + private final String userAgent = String.format("SocketLabs-java/%s(%s)", VERSION, JAVA_VERSION); + + private List
getDefaultHeaders() { + List
headers = Lists.newArrayList(new BasicHeader(HttpHeaders.USER_AGENT, this.userAgent)); + headers.add(new BasicHeader(HttpHeaders.CONTENT_TYPE, "application/json")); + headers.add(new BasicHeader(HttpHeaders.ACCEPT, "application/json")); + return headers; + } /** * Creates a new instance of the SocketLabsClient. @@ -82,19 +115,45 @@ public SendResponse send(BasicMessage message) throws Exception { if (result.getResult() != SendResult.Success) return result; - HttpRequest request = buildHttpRequest(this.proxy); + ApiKeyParser keyParser = new ApiKeyParser(); + ApiKeyParseResult parseResult = keyParser.Parse(this.apiKey); + this.useBearerAuth = (parseResult == ApiKeyParseResult.Success); + + String body = new InjectionRequestFactory(this.serverId, this.apiKey).GenerateRequest(message); + HttpPost httpPost = getHttpPost(body); + + CloseableHttpClient client = buildHttpClient(); + RetryHandler retryHandler = new RetryHandler(new RetrySettings(this.numberOfRetries)); + CloseableHttpResponse response = retryHandler.send(client, httpPost); + + InjectionResponseParser parser = new InjectionResponseParser(); + return parser.Parse(response); + } + + /** + * Synchronously sends a basic email message and returns the response from the Injection API. + * @param message A BasicMessage object to be sent. + * @return A SendResponse of an SocketLabsClient send request. + * @param httpClient A CloseableHttpClient instance to use when making http calls. + * @throws Exception exception + */ + @Override + public SendResponse send(BasicMessage message, CloseableHttpClient httpClient) throws Exception { + + SendResponse result = Validate(message); + if (result.getResult() != SendResult.Success) + return result; ApiKeyParser keyParser = new ApiKeyParser(); ApiKeyParseResult parseResult = keyParser.Parse(this.apiKey); + this.useBearerAuth = (parseResult == ApiKeyParseResult.Success); - if (parseResult != null && parseResult == ApiKeyParseResult.Success) - { - request.setHeader("Authorization", "Bearer " + this.apiKey); - } + String body = new InjectionRequestFactory(this.serverId, this.apiKey).GenerateRequest(message); + HttpPost httpPost = getHttpPost(body); - request.setBody(new InjectionRequestFactory(this.serverId, this.apiKey).GenerateRequest(message)); - RetryHandler retryHandler = new RetryHandler(request, this.endPointUrl, new RetrySettings(this.numberOfRetries)); - Response response = retryHandler.send(); + CloseableHttpClient client = buildHttpClient(); + RetryHandler retryHandler = new RetryHandler(new RetrySettings(this.numberOfRetries)); + CloseableHttpResponse response = retryHandler.send(client, httpPost); InjectionResponseParser parser = new InjectionResponseParser(); return parser.Parse(response); @@ -113,20 +172,46 @@ public SendResponse send(BulkMessage message) throws Exception { if (result.getResult() != SendResult.Success) return result; - HttpRequest request = buildHttpRequest(this.proxy); - ApiKeyParser keyParser = new ApiKeyParser(); ApiKeyParseResult parseResult = keyParser.Parse(this.apiKey); + this.useBearerAuth = (parseResult == ApiKeyParseResult.Success); - if (parseResult != null && parseResult == ApiKeyParseResult.Success) - { - request.setHeader("Authorization", "Bearer " + this.apiKey); - } + String body = new InjectionRequestFactory(this.serverId, this.apiKey).GenerateRequest(message); + HttpPost httpPost = getHttpPost(body); + + CloseableHttpClient client = buildHttpClient(); + RetryHandler retryHandler = new RetryHandler( new RetrySettings(this.numberOfRetries)); + CloseableHttpResponse response = retryHandler.send(client, httpPost); + + InjectionResponseParser parser = new InjectionResponseParser(); + return parser.Parse(response); + + } - request.setBody(new InjectionRequestFactory(this.serverId, this.apiKey).GenerateRequest(message)); + /** + * Synchronously sends a bulk email message and returns the response from the Injection API. + * @param message A BulkMessage object to be sent. + * @return A SendResponse of an SocketLabsClient send request. + * @param httpClient A CloseableHttpClient instance to use when making http calls. + * @throws Exception exception + */ + @Override + public SendResponse send(BulkMessage message, CloseableHttpClient httpClient) throws Exception { - RetryHandler retryHandler = new RetryHandler(request, this.endPointUrl, new RetrySettings(this.numberOfRetries)); - Response response = retryHandler.send(); + SendResponse result = Validate(message); + if (result.getResult() != SendResult.Success) + return result; + + ApiKeyParser keyParser = new ApiKeyParser(); + ApiKeyParseResult parseResult = keyParser.Parse(this.apiKey); + this.useBearerAuth = (parseResult == ApiKeyParseResult.Success); + + String body = new InjectionRequestFactory(this.serverId, this.apiKey).GenerateRequest(message); + HttpPost httpPost = getHttpPost(body); + + CloseableHttpClient client = buildHttpClient(); + RetryHandler retryHandler = new RetryHandler(new RetrySettings(this.numberOfRetries)); + CloseableHttpResponse response = retryHandler.send(client, httpPost); InjectionResponseParser parser = new InjectionResponseParser(); return parser.Parse(response); @@ -148,29 +233,84 @@ public void sendAsync(BasicMessage message, final SendAsyncCallback callback) th return; } - HttpRequest request = buildHttpRequest(this.proxy); - ApiKeyParser keyParser = new ApiKeyParser(); ApiKeyParseResult parseResult = keyParser.Parse(this.apiKey); + this.useBearerAuth = (parseResult == ApiKeyParseResult.Success); + + String body = new InjectionRequestFactory(this.serverId, this.apiKey).GenerateRequest(message); + HttpPost httpPost = getHttpPost(body); - if (parseResult != null && parseResult == ApiKeyParseResult.Success) - { - request.setHeader("Authorization", "Bearer " + this.apiKey); + InjectionResponseParser parser = new InjectionResponseParser(); + + CloseableHttpAsyncClient client = buildHttpAsyncClient(); + RetryHandler retryHandler = new RetryHandler(new RetrySettings(this.numberOfRetries)); + + retryHandler.sendAsync(client, httpPost, new FutureCallback() { + public void completed(final HttpResponse response) { + try { + callback.onResponse(parser.Parse(response)); + } catch (IOException ex) { + callback.onError(ex); + } + } + + public void failed(final Exception ex) { + callback.onError(ex); + } + + public void cancelled() { + callback.onError(new Exception("sendAsync cancelled")); + } + + }); + + } + + /** + * Asynchronously sends a basic email message and returns the response from the Injection API. + * @param message A BasicMessage object to be sent. + * @param httpAsyncClient A CloseableHttpAsyncClient instance to use when making http calls. + * @param callback A SendAsyncCallback to handle error and response from the Injection API. + * @throws Exception exception + */ + @Override + public void sendAsync(BasicMessage message, CloseableHttpAsyncClient httpAsyncClient, final SendAsyncCallback callback) throws Exception { + + SendResponse result = Validate(message); + if (result.getResult() != SendResult.Success) { + callback.onResponse(result); + return; } - request.setBody(new InjectionRequestFactory(this.serverId, this.apiKey).GenerateRequest(message)); + ApiKeyParser keyParser = new ApiKeyParser(); + ApiKeyParseResult parseResult = keyParser.Parse(this.apiKey); + this.useBearerAuth = (parseResult == ApiKeyParseResult.Success); + + String body = new InjectionRequestFactory(this.serverId, this.apiKey).GenerateRequest(message); + HttpPost httpPost = getHttpPost(body); - RetryHandler retryHandler = new RetryHandler(request, this.endPointUrl, new RetrySettings(this.numberOfRetries)); InjectionResponseParser parser = new InjectionResponseParser(); - retryHandler.sendAsync(new Callback() { - public void onResponse(Call call, Response response) throws IOException { - callback.onResponse(parser.Parse(response)); + CloseableHttpAsyncClient client = buildHttpAsyncClient(); + RetryHandler retryHandler = new RetryHandler(new RetrySettings(this.numberOfRetries)); + + retryHandler.sendAsync(client, httpPost, new FutureCallback() { + public void completed(final HttpResponse response) { + try { + callback.onResponse(parser.Parse(response)); + } catch (IOException ex) { + callback.onError(ex); + } } - public void onFailure(Call call, IOException ex) { + public void failed(final Exception ex) { callback.onError(ex); } + + public void cancelled() { + callback.onError(new Exception("sendAsync cancelled")); + } + }); } @@ -190,31 +330,85 @@ public void sendAsync(BulkMessage message, final SendAsyncCallback callback) thr return; } - HttpRequest request = buildHttpRequest(this.proxy); - ApiKeyParser keyParser = new ApiKeyParser(); ApiKeyParseResult parseResult = keyParser.Parse(this.apiKey); + this.useBearerAuth = (parseResult == ApiKeyParseResult.Success); - if (parseResult != null && parseResult == ApiKeyParseResult.Success) - { - request.setHeader("Authorization", "Bearer " + this.apiKey); - } - - request.setBody(new InjectionRequestFactory(this.serverId, this.apiKey).GenerateRequest(message)); + String body = new InjectionRequestFactory(this.serverId, this.apiKey).GenerateRequest(message); + HttpPost httpPost = getHttpPost(body); - RetryHandler retryHandler = new RetryHandler(request, this.endPointUrl, new RetrySettings(this.numberOfRetries)); InjectionResponseParser parser = new InjectionResponseParser(); - retryHandler.sendAsync(new Callback() { - public void onResponse(Call call, Response response) throws IOException { - callback.onResponse(parser.Parse(response)); + CloseableHttpAsyncClient client = buildHttpAsyncClient(); + RetryHandler retryHandler = new RetryHandler(new RetrySettings(this.numberOfRetries)); + + retryHandler.sendAsync(client, httpPost, new FutureCallback() { + public void completed(final HttpResponse response) { + try { + callback.onResponse(parser.Parse(response)); + } catch (IOException ex) { + callback.onError(ex); + } } - public void onFailure(Call call, IOException ex) { + public void failed(final Exception ex) { callback.onError(ex); } + + public void cancelled() { + callback.onError(new Exception("sendAsync cancelled")); + } + }); + } + + /** + * Asynchronously sends a bulk email message and returns the response from the Injection API. + * @param message A BulkMessage object to be sent. + * @param httpAsyncClient A CloseableHttpAsyncClient instance to use when making http calls. + * @param callback A SendAsyncCallback to handle error and response from the Injection API. + * @throws Exception exception + */ + @Override + public void sendAsync(BulkMessage message, CloseableHttpAsyncClient httpAsyncClient, final SendAsyncCallback callback) throws Exception { + + SendResponse result = Validate(message); + if (result.getResult() != SendResult.Success) { + callback.onResponse(result); + return; + } + + ApiKeyParser keyParser = new ApiKeyParser(); + ApiKeyParseResult parseResult = keyParser.Parse(this.apiKey); + this.useBearerAuth = (parseResult == ApiKeyParseResult.Success); + + String body = new InjectionRequestFactory(this.serverId, this.apiKey).GenerateRequest(message); + HttpPost httpPost = getHttpPost(body); + + InjectionResponseParser parser = new InjectionResponseParser(); + + CloseableHttpAsyncClient client = buildHttpAsyncClient(); + RetryHandler retryHandler = new RetryHandler(new RetrySettings(this.numberOfRetries)); + + retryHandler.sendAsync(client, httpPost, new FutureCallback() { + public void completed(final HttpResponse response) { + try { + callback.onResponse(parser.Parse(response)); + } catch (IOException ex) { + callback.onError(ex); + } + } + + public void failed(final Exception ex) { + callback.onError(ex); + } + + public void cancelled() { + callback.onError(new Exception("sendAsync cancelled")); + } + + }); } @@ -242,19 +436,60 @@ private SendResponse Validate(BulkMessage message) { } - private HttpRequest buildHttpRequest(Proxy optionalProxy) { + private CloseableHttpClient buildHttpClient() { + + PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); + cm.setMaxTotal(200); + cm.setDefaultMaxPerRoute(20); + cm.setValidateAfterInactivity(10000); - HttpRequest request = new HttpRequest(HttpRequest.HttpRequestMethod.POST, this.endPointUrl, this.requestTimeout); + return HttpClients.custom() + .setConnectionManager(cm) + .setDefaultRequestConfig(getDefaultRequestConfig()) + .build(); + } - request.setHeader("User-Agent", this.userAgent); - request.setHeader("content-type", "application/json"); - request.setHeader("Accept", "application/json"); + private CloseableHttpAsyncClient buildHttpAsyncClient() throws Exception { - if(optionalProxy != null) { - request.setProxy(optionalProxy); - } + final ConnectingIOReactor ioReactor = new DefaultConnectingIOReactor(); + PoolingNHttpClientConnectionManager cm = new PoolingNHttpClientConnectionManager(ioReactor); + cm.setMaxTotal(200); + cm.setDefaultMaxPerRoute(20); - return request; + return HttpAsyncClients.custom() + .setConnectionManager(cm) + .setDefaultRequestConfig(getDefaultRequestConfig()) + .build(); } + private RequestConfig getDefaultRequestConfig() { + return RequestConfig.custom() + .setConnectTimeout(this.requestTimeout) + .setConnectionRequestTimeout(this.requestTimeout) + .setSocketTimeout(this.requestTimeout) + .build(); + } + + private HttpPost getHttpPost(String body) throws UnsupportedEncodingException { + HttpPost httpPost = new HttpPost(this.endPointUrl); + StringEntity entity = new StringEntity(body); + httpPost.setEntity(entity); + + List
headers = getDefaultHeaders(); + for (Header header : headers) { + httpPost.addHeader(header); + } + if(this.useBearerAuth) { + httpPost.addHeader(new BasicHeader(HttpHeaders.AUTHORIZATION, "Bearer " + this.apiKey)); + } + + if (this.proxy != null) { + InetSocketAddress address = (InetSocketAddress) this.proxy.address(); + RequestConfig requestConfig = RequestConfig.copy(getDefaultRequestConfig()) + .setProxy(new HttpHost(address.getHostName(), address.getPort())) + .build(); + httpPost.setConfig(requestConfig); + } + return httpPost; + } } diff --git a/injectionApi/src/main/java/com/socketLabs/injectionApi/SocketLabsClientAPI.java b/injectionApi/src/main/java/com/socketLabs/injectionApi/SocketLabsClientAPI.java index 25fa695..e4c381b 100644 --- a/injectionApi/src/main/java/com/socketLabs/injectionApi/SocketLabsClientAPI.java +++ b/injectionApi/src/main/java/com/socketLabs/injectionApi/SocketLabsClientAPI.java @@ -3,6 +3,8 @@ import com.socketLabs.injectionApi.core.SendAsyncCallback; import com.socketLabs.injectionApi.message.BasicMessage; import com.socketLabs.injectionApi.message.BulkMessage; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; /** * SocketLabsClientAPI is an interface that defines the SocketLabs Injection API client and its public methods. @@ -17,6 +19,15 @@ public interface SocketLabsClientAPI { */ void sendAsync(BasicMessage message, final SendAsyncCallback callback) throws Exception; + /** + * Asynchronously sends a basic email message and returns the response from the Injection API. + * @param message A BasicMessage object to be sent. + * @param httpAsyncClient A CloseableHttpAsyncClient instance to use when making http calls. + * @param callback A SendAsyncCallback to handle error and response from the Injection API. + * @throws Exception exception + */ + void sendAsync(BasicMessage message, CloseableHttpAsyncClient httpAsyncClient, final SendAsyncCallback callback) throws Exception; + /** * Asynchronously sends a bulk email message and returns the response from the Injection API. * @param message A BulkMessage object to be sent. @@ -25,6 +36,17 @@ public interface SocketLabsClientAPI { */ void sendAsync(BulkMessage message, final SendAsyncCallback callback) throws Exception; + + /** + * Asynchronously sends a bulk email message and returns the response from the Injection API. + * @param message A BulkMessage object to be sent. + * @param httpAsyncClient A CloseableHttpAsyncClient instance to use when making http calls. + * @param callback A SendAsyncCallback to handle error and response from the Injection API. + * @throws Exception exception + */ + void sendAsync(BulkMessage message, CloseableHttpAsyncClient httpAsyncClient, final SendAsyncCallback callback) throws Exception; + + /** * Synchronously sends a basic email message and returns the response from the Injection API. * @param message A BasicMessage object to be sent. @@ -33,6 +55,15 @@ public interface SocketLabsClientAPI { */ SendResponse send(BasicMessage message) throws Exception; + /** + * Synchronously sends a basic email message and returns the response from the Injection API. + * @param message A BasicMessage object to be sent. + * @return A SendResponse of an SocketLabsClient send request. + * @param httpClient A CloseableHttpClient instance to use when making http calls. + * @throws Exception exception + */ + SendResponse send(BasicMessage message, CloseableHttpClient httpClient) throws Exception; + /** * Synchronously sends a bulk email message and returns the response from the Injection API. * @param message A BulkMessage object to be sent. @@ -40,4 +71,14 @@ public interface SocketLabsClientAPI { * @throws Exception exception */ SendResponse send(BulkMessage message) throws Exception; + + + /** + * Synchronously sends a bulk email message and returns the response from the Injection API. + * @param message A BulkMessage object to be sent. + * @return A SendResponse of an SocketLabsClient send request. + * @param httpClient A CloseableHttpClient instance to use when making http calls. + * @throws Exception exception + */ + SendResponse send(BulkMessage message, CloseableHttpClient httpClient) throws Exception; } diff --git a/injectionApi/src/main/java/com/socketLabs/injectionApi/core/HttpRequest.java b/injectionApi/src/main/java/com/socketLabs/injectionApi/core/HttpRequest.java index c559dcc..b6f67db 100644 --- a/injectionApi/src/main/java/com/socketLabs/injectionApi/core/HttpRequest.java +++ b/injectionApi/src/main/java/com/socketLabs/injectionApi/core/HttpRequest.java @@ -2,166 +2,65 @@ import com.socketLabs.injectionApi.SendResponse; import com.socketLabs.injectionApi.core.serialization.InjectionResponseParser; -import okhttp3.*; -import okhttp3.Request.Builder; - +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.concurrent.FutureCallback; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; import java.io.*; -import java.net.Proxy; -import java.util.concurrent.TimeUnit; -import java.util.HashMap; -import java.util.Map; +import java.util.concurrent.Future; /** * */ public class HttpRequest { - /** - * Enumeration of HTTP Request Methods - */ - public enum HttpRequestMethod { - GET, - POST, - PUT, - DELETE; - } - - /** The HTTP Request Method to use */ - private HttpRequestMethod method; - /** The URL to use for the HTTP request */ - private String endPointUrl; - /** The HTTP request body to send */ - private String body; - /** The Proxy to use when making the HTTP request */ - private Proxy proxy; - /** The headers to add to the HTTP Request */ - private Map headers = new HashMap<>(); - private int timeout; - - /** * Creates a new instance of the HTTP Request class - * @param method HTTpRequestMethod - * @param endPointUrl String - * @param timeout int - */ - public HttpRequest(HttpRequestMethod method, String endPointUrl, int timeout) { - this.method = method; - this.endPointUrl = endPointUrl; - this.timeout = timeout; - } - - /** - * Sets the HTTP request body - * @param value String - */ - public void setBody(String value) { - this.body = value; - } - - /** - * Sets the headers for the HTTP Request - * @param key String - * @param value String */ - public void setHeader(String key, String value) { - this.headers.put(key, value); - } - - /** - * Sets the Proxy to use when making the HTTP request - * @param value String - */ - public void setProxy(Proxy value) { this.proxy = value; } - - /** - * Media Type to use to force JSON - */ - public static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); + public HttpRequest() { } /** * Send the HTTP Request + * @param httpClient A CloseableHttpClient instance to use when making http calls. + * @param httpPost A HttpPost instance to send. * @return A SendResponse from the Injection Api response * @throws IOException in case of a network error. */ - public Response SendRequest() throws IOException { - - Call call = BuildClientCall(); - - Response response = call.execute(); - - return response; - + public CloseableHttpResponse SendRequest(CloseableHttpClient httpClient, HttpPost httpPost) throws IOException { + return httpClient.execute(httpPost); } /** - * Send an HTTP Request asynchronously + * Send an HTTP Request + * @param httpAsyncClient A CloseableHttpAsyncClient instance to use when making http calls. + * @param httpPost A HttpPost instance to send. * @param callback the SendAsyncCallback. + * @throws IOException in case of a network error. */ - public void SendAsyncRequest(final Callback callback) { - - Call call = BuildClientCall(); - - call.enqueue(new Callback() { - public void onResponse(Call call, Response response) throws IOException { - - callback.onResponse(call, response); - // ... - } - - public void onFailure(Call call, IOException ex) { - callback.onFailure(call, ex); - } - }); - - } - - - /** - * Build the HTTP Client call - * @return Call - */ - private Call BuildClientCall() { + public void SendAsyncRequest(CloseableHttpAsyncClient httpAsyncClient, HttpPost httpPost, final FutureCallback callback) throws IOException { - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder() - .connectTimeout(this.timeout, TimeUnit.SECONDS) - .writeTimeout(this.timeout, TimeUnit.SECONDS) - .readTimeout(this.timeout, TimeUnit.SECONDS) - .callTimeout(this.timeout, TimeUnit.SECONDS); + httpAsyncClient.start(); + final Future future = httpAsyncClient.execute(httpPost, + new FutureCallback() { - OkHttpClient client = clientBuilder.build(); + public void completed(final HttpResponse response) { + callback.completed(response); + } - if (this.proxy != null) - client = clientBuilder - .proxy(this.proxy) - .build(); + public void failed(final Exception exception) { + callback.failed(exception); + } - Builder builder = new Builder().url(this.endPointUrl); + public void cancelled() { + callback.cancelled(); + } - //add request method - RequestBody reqBody = RequestBody.create(JSON, this.body); - switch (this.method) { - case POST: - builder.post(reqBody); - break; - case GET: - builder.get(); - break; - case PUT: - builder.put(reqBody); - break; - case DELETE: - builder.delete(reqBody); - break; - } + }); - //add request header - for (Map.Entry header : this.headers.entrySet()) { - builder.addHeader(header.getKey(), header.getValue()); - } - - return client.newCall(builder.build()); + httpAsyncClient.close(); } @@ -169,10 +68,8 @@ private Call BuildClientCall() { * Parse the Response into a SendResponse * @param response the response from the HTTP request * @return SendResponse - * @throws IOException */ - private SendResponse ParseResponse(Response response) throws IOException { - + private SendResponse ParseResponse(HttpResponse response) throws IOException { InjectionResponseParser parser = new InjectionResponseParser(); return parser.Parse(response); diff --git a/injectionApi/src/main/java/com/socketLabs/injectionApi/core/RetryHandler.java b/injectionApi/src/main/java/com/socketLabs/injectionApi/core/RetryHandler.java index c0115e2..bd63499 100644 --- a/injectionApi/src/main/java/com/socketLabs/injectionApi/core/RetryHandler.java +++ b/injectionApi/src/main/java/com/socketLabs/injectionApi/core/RetryHandler.java @@ -1,11 +1,12 @@ package com.socketLabs.injectionApi.core; - import com.socketLabs.injectionApi.RetrySettings; -import com.socketLabs.injectionApi.core.serialization.InjectionResponseParser; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.Response; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.concurrent.FutureCallback; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; import java.io.IOException; import java.io.InterruptedIOException; @@ -14,38 +15,34 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; public class RetryHandler { - private HttpRequest httpRequest; - private String endPointUrl; - private RetrySettings retrySettings; + private final RetrySettings retrySettings; private int attempts = 0; - private Set ErrorStatusCodes = new HashSet<>(Arrays.asList(500, 502, 503, 504)); - private Set> Exceptions = new HashSet>(Arrays.asList( + private final Set ErrorStatusCodes = new HashSet<>(Arrays.asList(500, 502, 503, 504)); + private final Set> Exceptions = new HashSet>(Arrays.asList( SocketTimeoutException.class, InterruptedIOException.class )); - /// - /// Creates a new instance of the RetryHandler. - /// - /// A HttpRequest instance - /// The SocketLabs Injection API endpoint Url - /// A RetrySettings instance - public RetryHandler(HttpRequest request, String endpointUrl, RetrySettings settings){ - httpRequest = request; - endPointUrl = endpointUrl; - retrySettings = settings; + /** + * + * Creates a new instance of the RetryHandler. + * @param settings A RetrySettings instance. + */ + public RetryHandler(RetrySettings settings){ + this.retrySettings = settings; } - public Response send() throws IOException, InterruptedException { + + public CloseableHttpResponse send(CloseableHttpClient httpClient, HttpPost httpPost) throws IOException, InterruptedException { if (retrySettings.getMaximumNumberOfRetries() == 0) { - Response response = httpRequest.SendRequest(); - return response; + return httpClient.execute(httpPost); } do { @@ -53,10 +50,9 @@ public Response send() throws IOException, InterruptedException { Duration waitInterval = retrySettings.getNextWaitInterval(attempts); try{ - - Response response = httpRequest.SendRequest(); - if (ErrorStatusCodes.contains(response.networkResponse().code())) - throw new IOException("Received Http Status Code : " + response.networkResponse().code()); + CloseableHttpResponse response = httpClient.execute(httpPost); + if (ErrorStatusCodes.contains(response.getStatusLine().getStatusCode())) + throw new IOException("Received Http Status Code : " + response.getStatusLine().getStatusCode()); return response; } @@ -83,66 +79,80 @@ public Response send() throws IOException, InterruptedException { } - public void sendAsync (final Callback callback) throws IOException, InterruptedException{ + public void sendAsync (CloseableHttpAsyncClient httpAsyncClient, HttpPost httpPost, final FutureCallback callback) throws IOException, InterruptedException{ - InjectionResponseParser parser = new InjectionResponseParser(); Duration waitInterval = retrySettings.getNextWaitInterval(attempts); - httpRequest.SendAsyncRequest(new Callback() { + // Create a default CloseableHttpAsyncClient instance + try { + // Start the client + httpAsyncClient.start(); + + // Use a CountDownLatch to wait for the asynchronous operation to complete + final CountDownLatch latch = new CountDownLatch(1); + + // Execute the request asynchronously with a FutureCallback + httpAsyncClient.execute(httpPost, new FutureCallback() { + @Override + public void completed(final HttpResponse response) { + if (ErrorStatusCodes.contains(response.getStatusLine().getStatusCode()) && attempts <= retrySettings.getMaximumNumberOfRetries()){ + attempts++; + + try { + TimeUnit.MILLISECONDS.sleep(waitInterval.toMillis()); + sendAsync(httpAsyncClient, httpPost, callback); + } + catch (IOException | InterruptedException ioException) { + callback.failed(ioException); + } + } - @Override - public void onResponse(Call call, Response response) throws IOException { + else { + callback.completed(response); + } + latch.countDown(); // Signal completion + } - if (ErrorStatusCodes.contains(response.networkResponse().code()) && attempts <= retrySettings.getMaximumNumberOfRetries()){ + @Override + public void failed(final Exception exception) { + if(Exceptions.contains(exception.getClass()) && attempts <= retrySettings.getMaximumNumberOfRetries()) { + attempts++; - attempts++; + try { + TimeUnit.MILLISECONDS.sleep(waitInterval.toMillis()); + sendAsync(httpAsyncClient, httpPost, callback); + } + catch (IOException | InterruptedException ioException) { + callback.failed(ioException); + } - try { - TimeUnit.MILLISECONDS.sleep(waitInterval.toMillis()); - sendAsync(callback); } - catch (InterruptedException interruptedException) { - interruptedException.printStackTrace(); + else { + attempts = retrySettings.getMaximumNumberOfRetries() + 1; + callback.failed(exception); } - + latch.countDown(); // Signal completion even on failure } - else { - callback.onResponse(call, response); + @Override + public void cancelled() { + callback.cancelled(); + latch.countDown(); // Signal completion on cancellation } + }); - } - - @Override - public void onFailure(Call call, IOException exception) { - - if(Exceptions.contains(exception.getClass()) && attempts <= retrySettings.getMaximumNumberOfRetries()) { - - attempts++; + // Wait for the asynchronous operation to complete + latch.await(); - try { - TimeUnit.MILLISECONDS.sleep(waitInterval.toMillis()); - sendAsync(callback); - } - - catch (IOException ioException) { - ioException.printStackTrace(); - } - - catch (InterruptedException interruptedException) { - interruptedException.printStackTrace(); - } - - } - else { - attempts = retrySettings.getMaximumNumberOfRetries() + 1; - callback.onFailure(call, exception); - } + } catch (Exception exception) { + callback.failed(exception); + } finally { + httpAsyncClient.close(); + } - } - }); } + } diff --git a/injectionApi/src/main/java/com/socketLabs/injectionApi/core/SendAsyncCallback.java b/injectionApi/src/main/java/com/socketLabs/injectionApi/core/SendAsyncCallback.java index e438b05..6e64b93 100644 --- a/injectionApi/src/main/java/com/socketLabs/injectionApi/core/SendAsyncCallback.java +++ b/injectionApi/src/main/java/com/socketLabs/injectionApi/core/SendAsyncCallback.java @@ -1,7 +1,6 @@ package com.socketLabs.injectionApi.core; import com.socketLabs.injectionApi.SendResponse; -import okhttp3.Call; import java.io.IOException; diff --git a/injectionApi/src/main/java/com/socketLabs/injectionApi/core/serialization/InjectionResponseParser.java b/injectionApi/src/main/java/com/socketLabs/injectionApi/core/serialization/InjectionResponseParser.java index fc0912e..8a9a131 100644 --- a/injectionApi/src/main/java/com/socketLabs/injectionApi/core/serialization/InjectionResponseParser.java +++ b/injectionApi/src/main/java/com/socketLabs/injectionApi/core/serialization/InjectionResponseParser.java @@ -2,7 +2,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.socketLabs.injectionApi.*; -import okhttp3.Response; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.util.EntityUtils; import java.io.IOException; @@ -17,12 +20,46 @@ public class InjectionResponseParser { * @return A SendResponse from the Injection Api response * @throws IOException in case of a network error. */ - public SendResponse Parse(Response response) throws IOException { + public SendResponse Parse(HttpResponse response) throws IOException { ObjectMapper mapper = new ObjectMapper(); - InjectionResponseDto injectionResponse = mapper.readValue(response.body().string(), InjectionResponseDto.class); + HttpEntity body = response.getEntity(); + String responseBody = EntityUtils.toString(body, "UTF-8"); - SendResult resultEnum = DetermineSendResult(injectionResponse, response.networkResponse().code()); + InjectionResponseDto injectionResponse = mapper.readValue(responseBody, InjectionResponseDto.class); + + SendResult resultEnum = DetermineSendResult(injectionResponse, response.getStatusLine().getStatusCode()); + SendResponse newResponse = new SendResponse(resultEnum); + newResponse.setTransactionReceipt(injectionResponse.getTransactionReceipt()); + + if (resultEnum == SendResult.Warning && (injectionResponse.getMessageResults() != null && injectionResponse.getMessageResults().size() > 0)) + { + SendResult r = SendResult.fromString(injectionResponse.getMessageResults().get(0).getErrorCode()); + newResponse.setResult(r); + } + + if (injectionResponse.getMessageResults() != null && injectionResponse.getMessageResults().size() > 0) + newResponse.setAddressResults(injectionResponse.getMessageResults().get(0).getAddressResults()); + + return newResponse; + + } + + /** + * Parse the response from theInjection Api into SendResponse + * @param response The response from the Injection Api request + * @return A SendResponse from the Injection Api response + * @throws IOException in case of a network error. + */ + public SendResponse Parse(CloseableHttpResponse response) throws IOException { + + ObjectMapper mapper = new ObjectMapper(); + HttpEntity body = response.getEntity(); + String responseBody = EntityUtils.toString(body, "UTF-8"); + + InjectionResponseDto injectionResponse = mapper.readValue(responseBody, InjectionResponseDto.class); + + SendResult resultEnum = DetermineSendResult(injectionResponse, response.getStatusLine().getStatusCode()); SendResponse newResponse = new SendResponse(resultEnum); newResponse.setTransactionReceipt(injectionResponse.getTransactionReceipt());