From d566a087c586094ed4659b3665ae5b109d2d9e2c Mon Sep 17 00:00:00 2001 From: Evan Williams Date: Mon, 5 Dec 2016 14:43:26 -0500 Subject: [PATCH 1/5] Add sendFax InputStream Methods Add methods to the API that implement sendFax using an array of InputStreams rather than an array of files. --- .../net/interfax/rest/client/InterFAX.java | 31 +++++++++++++++- .../client/impl/DefaultInterFAXClient.java | 35 +++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/interfax/rest/client/InterFAX.java b/src/main/java/net/interfax/rest/client/InterFAX.java index fc1ccd6..240f3eb 100644 --- a/src/main/java/net/interfax/rest/client/InterFAX.java +++ b/src/main/java/net/interfax/rest/client/InterFAX.java @@ -15,6 +15,7 @@ import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.util.Optional; public interface InterFAX { @@ -45,7 +46,7 @@ public interface InterFAX { public APIResponse sendFax(final String faxNumber, final File fileToSendAsFax, final Optional options) throws IOException; - + /** * Send an array of files as a fax * @@ -57,6 +58,18 @@ public APIResponse sendFax(final String faxNumber, */ public APIResponse sendFax(final String faxNumber, final File[] filesToSendAsFax) throws IOException; + /** + * Send an array of input streams as a fax + * + * @param faxNumber number to fax to + * @param streamsToSendAsFax array of input streams to send as fax + * @param fileNames array of file names corresponding to the input streams (for mime detection) + * @return {@link APIResponse} + * @throws IOException + * @see https://www.interfax.net/en/dev/rest/reference/2918 + */ + public APIResponse sendFax(final String faxNumber, final InputStream[] streamsToSendAsFax, final String fileNames[]) throws IOException; + /** * Send an array of files as a fax with additional {@link SendFaxOptions} * @@ -71,6 +84,22 @@ public APIResponse sendFax(final String faxNumber, final File[] filesToSendAsFax, final Optional options) throws IOException; + /** + * Send an array of files as a fax with additional {@link SendFaxOptions} + * + * @param faxNumber number to fax to + * @param streamsToSendAsFax array of files to send as fax + * @param fileNames array of file names corresponding to the input streams (for mime detection) + * @param options {@link SendFaxOptions} to use when sending the fax + * @return {@link APIResponse} + * @throws IOException + * @see https://www.interfax.net/en/dev/rest/reference/2918 + */ + public APIResponse sendFax(final String faxNumber, + final InputStream[] streamsToSendAsFax, + final String fileNames[], + final Optional options) throws IOException; + /** * Send a pre-uploaded document, available on a HTTP url, as a fax * diff --git a/src/main/java/net/interfax/rest/client/impl/DefaultInterFAXClient.java b/src/main/java/net/interfax/rest/client/impl/DefaultInterFAXClient.java index 384a3f4..79cb680 100644 --- a/src/main/java/net/interfax/rest/client/impl/DefaultInterFAXClient.java +++ b/src/main/java/net/interfax/rest/client/impl/DefaultInterFAXClient.java @@ -25,6 +25,7 @@ import org.glassfish.jersey.media.multipart.MultiPart; import org.glassfish.jersey.media.multipart.MultiPartFeature; import org.glassfish.jersey.media.multipart.file.FileDataBodyPart; +import org.glassfish.jersey.media.multipart.file.StreamDataBodyPart; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -121,6 +122,12 @@ public APIResponse sendFax(final String faxNumber, final File[] filesToSendAsFax return sendFax(faxNumber, filesToSendAsFax, Optional.empty()); } + @Override + public APIResponse sendFax(String faxNumber, InputStream[] streamsToSendAsFax, String[] fileNames) + throws IOException { + return sendFax(faxNumber, streamsToSendAsFax, fileNames, Optional.empty()); + } + @Override public APIResponse sendFax(final String faxNumber, final File[] filesToSendAsFax, @@ -147,6 +154,34 @@ public APIResponse sendFax(final String faxNumber, ); } + @Override + public APIResponse sendFax(String faxNumber, InputStream[] streamsToSendAsFax, String[] fileNames, + Optional options) throws IOException { + + if (streamsToSendAsFax.length != fileNames.length) { + throw new IllegalArgumentException("Stream and file name arrays do not have the same length"); + } + + MultiPart multiPart = new MultiPart(); + for (int i=0; i < streamsToSendAsFax.length; i++) { + final String contentType = tika.detect(fileNames[i]); + final String entityName = fileNames[i]; + final StreamDataBodyPart streamDataBodyPart = new StreamDataBodyPart(entityName, streamsToSendAsFax[i], entityName, MediaType.valueOf(contentType)); + multiPart.bodyPart(streamDataBodyPart); + } + + final URI outboundFaxesUri = getSendFaxUri(faxNumber, options); + return executePostRequest( + outboundFaxesUri, + Entity.entity(multiPart, multiPart.getMediaType()), + (target) -> + target + .request() + .header("Content-Type", "multipart/mixed") + .post(Entity.entity(multiPart, multiPart.getMediaType())) + ); + } + @Override public APIResponse sendFax(final String faxNumber, final String urlOfDoc) { From e07acf130148d4d8b0db601e0e5e55f8d61d4812 Mon Sep 17 00:00:00 2001 From: Evan Williams Date: Mon, 5 Dec 2016 15:25:20 -0500 Subject: [PATCH 2/5] Unit tests for sendFax with InputStreams These are unit tests to test the added sendFax methods that send a fax using input streams --- .../impl/DefaultInterFAXClientTest.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/test/java/net/interfax/rest/client/impl/DefaultInterFAXClientTest.java b/src/test/java/net/interfax/rest/client/impl/DefaultInterFAXClientTest.java index 38cbc40..a92e588 100644 --- a/src/test/java/net/interfax/rest/client/impl/DefaultInterFAXClientTest.java +++ b/src/test/java/net/interfax/rest/client/impl/DefaultInterFAXClientTest.java @@ -21,6 +21,8 @@ import org.junit.Test; import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; import java.util.Optional; @@ -91,6 +93,42 @@ public void testSendMultipleFilesAsFaxWithOptions() throws Exception { Assert.assertEquals(201, apiResponse.getStatusCode()); } + + @Test + public void testSendMultipleInputStreamsAsFax() throws Exception { + + String absoluteFilePath = this.getClass().getClassLoader().getResource("test.pdf").getFile(); + InputStream inputStream1 = new FileInputStream(absoluteFilePath); + InputStream inputStream2 = new FileInputStream(absoluteFilePath); + + InputStream[] inputStreams = {inputStream1, inputStream2}; + String[] fileNames = {"test.pdf", "test.pdf"}; + + InterFAX interFAX = new DefaultInterFAXClient(); + APIResponse apiResponse = interFAX.sendFax(faxNumber, inputStreams, fileNames); + Assert.assertEquals("[https://rest.interfax.net/outbound/faxes/667457707]", apiResponse.getHeaders().get("Location").toString()); + Assert.assertEquals(201, apiResponse.getStatusCode()); + } + + @Test + public void testSendMultipleInputStreamsAsFaxWithOptions() throws Exception { + + String absoluteFilePath = this.getClass().getClassLoader().getResource("test.pdf").getFile(); + InputStream inputStream1 = new FileInputStream(absoluteFilePath); + InputStream inputStream2 = new FileInputStream(absoluteFilePath); + + InputStream[] inputStreams = {inputStream1, inputStream2}; + String[] fileNames = {"test.pdf", "test.pdf"}; + + SendFaxOptions sendFaxOptions = new SendFaxOptions(); + sendFaxOptions.setPageSize(Optional.of("a4")); + + InterFAX interFAX = new DefaultInterFAXClient(); + APIResponse apiResponse = interFAX.sendFax(faxNumber, inputStreams, fileNames, Optional.of(sendFaxOptions)); + Assert.assertEquals("[https://rest.interfax.net/outbound/faxes/667457707]", apiResponse.getHeaders().get("Location").toString()); + Assert.assertEquals(201, apiResponse.getStatusCode()); + + } @Test public void testSendFaxUsingPreviouslyUploadedDocUrl() throws Exception { From d826dca74b36f5472856dedd92a3b8afa6c97d0a Mon Sep 17 00:00:00 2001 From: Evan Williams Date: Wed, 24 Oct 2018 15:39:40 -0400 Subject: [PATCH 3/5] Say 0.14 --- README.md | 2 +- .../net/interfax/rest/client/impl/DefaultInterFAXClient.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b1c7fda..3a9019c 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Use of the library requires Java 8 or higher and can be done via one of the foll net.interfax api-client - 0.12 + 0.14 ``` diff --git a/src/main/java/net/interfax/rest/client/impl/DefaultInterFAXClient.java b/src/main/java/net/interfax/rest/client/impl/DefaultInterFAXClient.java index 703ac34..999ad4e 100644 --- a/src/main/java/net/interfax/rest/client/impl/DefaultInterFAXClient.java +++ b/src/main/java/net/interfax/rest/client/impl/DefaultInterFAXClient.java @@ -711,4 +711,4 @@ private void initializeClient(String username, String password) { reentrantLock.unlock(); } } -} \ No newline at end of file +} From c67d66c33b5f37db1342f0bc54aabfd6a6b496b3 Mon Sep 17 00:00:00 2001 From: Evan Williams Date: Fri, 26 Oct 2018 14:54:54 -0400 Subject: [PATCH 4/5] Document Errors Document upload and send uploaded document were getting a code 411 because the content length was not being sent. This is because Java began filtering content length because it is considered dangerous to be settable. This fix repairs that problem by sending actal zero byte content which circumvents the issue. --- .../net/interfax/rest/client/impl/DefaultInterFAXClient.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/interfax/rest/client/impl/DefaultInterFAXClient.java b/src/main/java/net/interfax/rest/client/impl/DefaultInterFAXClient.java index 999ad4e..6e37c39 100644 --- a/src/main/java/net/interfax/rest/client/impl/DefaultInterFAXClient.java +++ b/src/main/java/net/interfax/rest/client/impl/DefaultInterFAXClient.java @@ -163,7 +163,7 @@ public APIResponse sendFax(final String faxNumber, final String urlOfDoc, final URI uri = getSendFaxUri(faxNumber, options); return executePostRequest( uri, - target -> target.request().header("Content-Location", urlOfDoc).header("Content-Length", 0).post(null) + target -> target.request().header("Content-Location", urlOfDoc).header("Content-Length", 0).post(Entity.entity(new byte[0], MediaType.APPLICATION_OCTET_STREAM_TYPE)) ); } @@ -323,7 +323,7 @@ public APIResponse uploadDocument(final File fileToUpload, final Optional Date: Tue, 29 Jan 2019 13:47:14 -0500 Subject: [PATCH 5/5] Allow 204s The current code code of the uploadChunk method allowed 200 and 202 as valid response codes. However, the server also sends 204s and the method incorrectly identified this as an error. This commit corrects that. --- .../rest/client/impl/DefaultInterFAXClient.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/interfax/rest/client/impl/DefaultInterFAXClient.java b/src/main/java/net/interfax/rest/client/impl/DefaultInterFAXClient.java index 6e37c39..f40152f 100644 --- a/src/main/java/net/interfax/rest/client/impl/DefaultInterFAXClient.java +++ b/src/main/java/net/interfax/rest/client/impl/DefaultInterFAXClient.java @@ -390,11 +390,14 @@ public APIResponse uploadChunk(String uploadChunkToDocumentEndpoint, .header("Range", "bytes="+startByteRange+"-"+endByteRange) .post(Entity.entity(bytesToUpload, MediaType.APPLICATION_OCTET_STREAM_TYPE)); - int expectedResponseCode = lastChunk ? - Response.Status.OK.getStatusCode(): - Response.Status.ACCEPTED.getStatusCode(); - if (response.getStatus() == expectedResponseCode) { + final int OK = Response.Status.OK.getStatusCode(); + final int ACCEPTED = Response.Status.ACCEPTED.getStatusCode(); + final int NO_CONTENT = Response.Status.NO_CONTENT.getStatusCode(); // 204: No content + + + if ((lastChunk && response.getStatus() == OK) || + (!lastChunk && (response.getStatus() == ACCEPTED || response.getStatus() == NO_CONTENT))) { log.info( "chunk uploaded at {}; totalByesUploaded = {}; lastChunk = {}", uploadChunkToDocumentEndpoint,