Merge pull request #10840 from iulian-manda/master
BAEL-4856 Download a binary file using OkHttp
This commit is contained in:
commit
5e909f0750
|
@ -0,0 +1,38 @@
|
||||||
|
package com.baeldung.okhttp.download;
|
||||||
|
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
import okhttp3.ResponseBody;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static org.springframework.http.HttpHeaders.CONTENT_LENGTH;
|
||||||
|
|
||||||
|
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 = new Request.Builder().url(url).build();
|
||||||
|
Response response = client.newCall(request).execute();
|
||||||
|
ResponseBody responseBody = response.body();
|
||||||
|
if (responseBody == null) {
|
||||||
|
throw new IllegalStateException("Response doesn't contain a file");
|
||||||
|
}
|
||||||
|
double length = Double.parseDouble(Objects.requireNonNull(response.header(CONTENT_LENGTH, "1")));
|
||||||
|
return writer.write(responseBody.byteStream(), length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws Exception {
|
||||||
|
writer.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
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;
|
||||||
|
private final ProgressCallback progressCallback;
|
||||||
|
|
||||||
|
public BinaryFileWriter(OutputStream outputStream, ProgressCallback progressCallback) {
|
||||||
|
this.outputStream = outputStream;
|
||||||
|
this.progressCallback = progressCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long write(InputStream inputStream, double length) 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);
|
||||||
|
progressCallback.onProgress(totalBytes / length * 100.0);
|
||||||
|
}
|
||||||
|
return totalBytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
outputStream.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.baeldung.okhttp.download;
|
||||||
|
|
||||||
|
public interface ProgressCallback {
|
||||||
|
|
||||||
|
void onProgress(double progress);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package com.baeldung.okhttp.download;
|
||||||
|
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.mockwebserver.MockResponse;
|
||||||
|
import okhttp3.mockwebserver.MockWebServer;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
public class BinaryFileDownloaderIntegrationTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public MockWebServer server = new MockWebServer();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenATextFile_whenDownload_thenExpectFileDownloaded() {
|
||||||
|
String body = "Hello Baeldung Readers!";
|
||||||
|
server.enqueue(new MockResponse().setBody(body));
|
||||||
|
String fileName = "download.txt";
|
||||||
|
|
||||||
|
ProgressCallback progressCallback = progress -> assertEquals(100.0, progress, .0);
|
||||||
|
try (BinaryFileWriter writer = new BinaryFileWriter(new FileOutputStream(fileName), progressCallback); BinaryFileDownloader tested = new BinaryFileDownloader(new OkHttpClient(), writer)) {
|
||||||
|
long downloaded = tested.download(server.url("/greetings").toString());
|
||||||
|
assertEquals(body.length(), downloaded);
|
||||||
|
File downloadedFile = new File(fileName);
|
||||||
|
assertTrue(downloadedFile.isFile());
|
||||||
|
assertTrue(downloadedFile.delete());
|
||||||
|
} catch (Exception e) {
|
||||||
|
fail("An unexpected exception has occurred: " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
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.Assert.assertEquals;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyDouble;
|
||||||
|
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 BinaryFileDownloaderUnitTest {
|
||||||
|
|
||||||
|
@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(), anyDouble())).thenReturn(1L);
|
||||||
|
|
||||||
|
try (BinaryFileDownloader tested = new BinaryFileDownloader(client, writer)) {
|
||||||
|
long size = tested.download(url);
|
||||||
|
assertEquals(1L, size);
|
||||||
|
verify(writer).write(any(InputStream.class), anyDouble());
|
||||||
|
}
|
||||||
|
verify(writer).close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalStateException.class)
|
||||||
|
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);
|
||||||
|
|
||||||
|
tested.download(url);
|
||||||
|
|
||||||
|
verify(writer, times(0)).write(any(InputStream.class), anyDouble());
|
||||||
|
}
|
||||||
|
|
||||||
|
@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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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.Assert.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 BinaryFileWriterUnitTest {
|
||||||
|
|
||||||
|
@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, progress -> assertEquals(100.0, progress, .0))) {
|
||||||
|
long result = tested.write(inputStream, 10);
|
||||||
|
|
||||||
|
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, progress -> assertEquals(100.0, progress, .0))) {
|
||||||
|
long result = tested.write(inputStream, 1);
|
||||||
|
|
||||||
|
assertEquals(0, result);
|
||||||
|
verify(outputStream, times(0)).write(any(), anyInt(), anyInt());
|
||||||
|
verify(inputStream).close();
|
||||||
|
}
|
||||||
|
verify(outputStream).close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue