diff --git a/libraries-http-2/src/main/java/com/baeldung/okhttp/download/BinaryFileDownloadApplication.java b/libraries-http-2/src/main/java/com/baeldung/okhttp/download/BinaryFileDownloadApplication.java new file mode 100644 index 0000000000..f350fe6f6e --- /dev/null +++ b/libraries-http-2/src/main/java/com/baeldung/okhttp/download/BinaryFileDownloadApplication.java @@ -0,0 +1,26 @@ +package com.baeldung.okhttp.download; + +import okhttp3.OkHttpClient; + +import java.io.FileOutputStream; + +public class BinaryFileDownloadApplication { + + public static void main(String[] args) { + String url = args[0]; + String file = args[1]; + try (BinaryFileDownloader downloader = new BinaryFileDownloader(new OkHttpClient(), + new BinaryFileWriter(new FileOutputStream(file)))) { + long downloadSize = downloader.download(url); + double downloadSizeInMB = convertToMB(downloadSize); + System.out.printf("Successfully downloaded file %s from %s. Total size %.2fMB%n", file, url, downloadSizeInMB); + } catch (Exception ex) { + System.err.printf("Could not download file %s from %s. %nError: %s%n", file, url, ex); + } + } + + private static double convertToMB(double downloadSize) { + return downloadSize / (1024.0 * 1024.0); + } + +} diff --git a/libraries-http-2/src/main/java/com/baeldung/okhttp/download/BinaryFileDownloader.java b/libraries-http-2/src/main/java/com/baeldung/okhttp/download/BinaryFileDownloader.java new file mode 100644 index 0000000000..f4c98751f4 --- /dev/null +++ b/libraries-http-2/src/main/java/com/baeldung/okhttp/download/BinaryFileDownloader.java @@ -0,0 +1,54 @@ +package com.baeldung.okhttp.download; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; + +public class BinaryFileDownloader implements AutoCloseable { + + private final OkHttpClient client; + private final BinaryFileWriter writer; + + public BinaryFileDownloader(OkHttpClient client, BinaryFileWriter writer) { + this.client = client; + this.writer = writer; + } + + public long download(String url) throws IOException { + Request request = createRequest(url); + Response response = executeRequest(request); + ResponseBody responseBody = getResponseBodyOrFail(response); + return write(responseBody); + } + + @NotNull + private Request createRequest(String url) { + return new Request.Builder().url(url).build(); + } + + @NotNull + private Response executeRequest(Request request) throws IOException { + return client.newCall(request).execute(); + } + + private ResponseBody getResponseBodyOrFail(Response response) { + ResponseBody responseBody = response.body(); + if (responseBody == null) { + throw new IllegalStateException("Response doesn't contain a file"); + } + return responseBody; + } + + private long write(ResponseBody responseBody) throws IOException { + return writer.write(responseBody.byteStream()); + } + + @Override + public void close() throws Exception { + writer.close(); + } +} diff --git a/libraries-http-2/src/main/java/com/baeldung/okhttp/download/BinaryFileWriter.java b/libraries-http-2/src/main/java/com/baeldung/okhttp/download/BinaryFileWriter.java new file mode 100644 index 0000000000..95f91e26b2 --- /dev/null +++ b/libraries-http-2/src/main/java/com/baeldung/okhttp/download/BinaryFileWriter.java @@ -0,0 +1,34 @@ +package com.baeldung.okhttp.download; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class BinaryFileWriter implements AutoCloseable { + + private static final int CHUNK_SIZE = 1024; + private final OutputStream outputStream; + + public BinaryFileWriter(OutputStream outputStream) { + this.outputStream = outputStream; + } + + public long write(InputStream inputStream) throws IOException { + try (BufferedInputStream input = new BufferedInputStream(inputStream)) { + byte[] dataBuffer = new byte[CHUNK_SIZE]; + int readBytes; + long totalBytes = 0; + while ((readBytes = input.read(dataBuffer)) != -1) { + totalBytes += readBytes; + outputStream.write(dataBuffer, 0, readBytes); + } + return totalBytes; + } + } + + @Override + public void close() throws IOException { + outputStream.close(); + } +} diff --git a/libraries-http-2/src/test/java/com/baeldung/okhttp/download/BinaryFileDownloaderTest.java b/libraries-http-2/src/test/java/com/baeldung/okhttp/download/BinaryFileDownloaderTest.java new file mode 100644 index 0000000000..aa189a9ff0 --- /dev/null +++ b/libraries-http-2/src/test/java/com/baeldung/okhttp/download/BinaryFileDownloaderTest.java @@ -0,0 +1,80 @@ +package com.baeldung.okhttp.download; + +import okhttp3.Call; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; +import org.jetbrains.annotations.NotNull; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.io.InputStream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class BinaryFileDownloaderTest { + + @Mock + private OkHttpClient client; + @Mock + private BinaryFileWriter writer; + @InjectMocks + private BinaryFileDownloader tested; + + @Test + public void givenUrlAndResponse_whenDownload_thenExpectFileWritten() throws Exception { + String url = "http://example.com/file"; + Call call = mock(Call.class); + when(client.newCall(any(Request.class))).thenReturn(call); + ResponseBody body = ResponseBody.create("BODY", MediaType.get("application/text")); + Response response = createResponse(url, body); + when(call.execute()).thenReturn(response); + when(writer.write(any())).thenReturn(1L); + + try (BinaryFileDownloader tested = new BinaryFileDownloader(client, writer)) { + long size = tested.download(url); + assertEquals(1L, size); + verify(writer).write(any(InputStream.class)); + } + verify(writer).close(); + } + + @Test + public void givenUrlAndResponseWithNullBody_whenDownload_thenExpectIllegalStateException() throws Exception { + String url = "http://example.com/file"; + Call call = mock(Call.class); + when(client.newCall(any(Request.class))).thenReturn(call); + Response response = createResponse(url, null); + when(call.execute()).thenReturn(response); + + assertThrows(IllegalStateException.class, () -> tested.download(url)); + + verify(writer, times(0)).write(any(InputStream.class)); + } + + @NotNull + private Response createResponse(String url, ResponseBody body) { + Request request = new Request.Builder().url(url).build(); + return new Response.Builder() + .code(200) + .request(request) + .protocol(Protocol.HTTP_2) + .message("Message") + .body(body) + .build(); + } + +} \ No newline at end of file diff --git a/libraries-http-2/src/test/java/com/baeldung/okhttp/download/BinaryFileWriterTest.java b/libraries-http-2/src/test/java/com/baeldung/okhttp/download/BinaryFileWriterTest.java new file mode 100644 index 0000000000..b74b2d1987 --- /dev/null +++ b/libraries-http-2/src/test/java/com/baeldung/okhttp/download/BinaryFileWriterTest.java @@ -0,0 +1,55 @@ +package com.baeldung.okhttp.download; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.io.InputStream; +import java.io.OutputStream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class BinaryFileWriterTest { + + @Mock + private OutputStream outputStream; + + @Test + public void givenInputStream_whenWrite_thenExpectWritten() throws Exception { + InputStream inputStream = mock(InputStream.class); + when(inputStream.read(any(), anyInt(), anyInt())).thenReturn(10, -1); + + try (BinaryFileWriter tested = new BinaryFileWriter(outputStream)) { + long result = tested.write(inputStream); + + assertEquals(10, result); + verify(outputStream).write(any(), eq(0), eq(10)); + verify(inputStream).close(); + } + verify(outputStream).close(); + } + + @Test + public void givenInputStreamEmpty_whenWrite_thenExpectNotWritten() throws Exception { + InputStream inputStream = mock(InputStream.class); + + try (BinaryFileWriter tested = new BinaryFileWriter(outputStream)) { + long result = tested.write(inputStream); + + assertEquals(0, result); + verify(outputStream, times(0)).write(any(), anyInt(), anyInt()); + verify(inputStream).close(); + } + verify(outputStream).close(); + } + +} \ No newline at end of file