Print download percent with okHttp spring boot - spring

I have a cron job with the task of downloading zip files from the server. I am using okHttp and FileUtils.copyInputStreamToFile().
My cron job below:
public void getFile() throws IOException {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(GlobalVariables.DOWNLOAD_URL)
.addHeader("Authorization","Bearer " + authentication())
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) {
throw new IOException("Failed to download file: " + response);
}
FileUtils.copyInputStreamToFile(Objects.requireNonNull(response.body()).byteStream(), new File(GlobalVariables.SAVE_DIR));
response.close();
}
How can I print the percentage downloaded in console? Thanks alot for the reply.

Related

Call RestApi endpoint resource from EJB

I have been looking around for sample code how to call a Restful service written in Spring boot (deployed in different server/ip) from an EJB client.
I couldn't find a simple example or reference to guide me on how to implement an EJB client that can call a restful service(deployed in different server/ip). Could you please point me to a document or example that shows or describe how the two can interface/talk to each other.
I need to call the endpoint by passing two header parameters for authentication, if authentication is success then only retrieve the details from Rest and send back the response to EJB client.
I use something like this, try
`public void calExternal() throws ProtocolException,
MalformedURLException,
IOException,
NoSuchAlgorithmException,
InvalidKeyException {
URL myurl = new URL("API END POINT URL");
ObjectMapper mapper = new ObjectMapper();
HttpURLConnection conn = (HttpURLConnection) myurl.openConnection();
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(true);
String payLoad = mapper.writeValueAsString("your payload here");
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("AUTHORIZATION-TYPE", "HMAC");
try {
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(payLoad);
wr.flush();
InputStream in = null;
int responseCode = conn.getResponseCode();
if (responseCode == 200) {
in = conn.getInputStream();
} else {
in = conn.getErrorStream();
}
String encoding = conn.getContentEncoding() == null ? "UTF-8" : conn.getContentEncoding();
String response = IOUtils.toString(in, encoding);
} catch (Exception e) {
e.printStackTrace();
}
}

Pact consumer test does not successfully mock the spring webclient request using the created pact

I am new to Pact Contract testing and I am trying to create a Pact consumer test to validate a method that calls an api with get request. The api request is made using Spring Webclient.
I am not able to create the webclient object by just providing the Pact mockserver eg.
WebClient webClient = WebClient.builder().baseUrl(mockServer.getUrl()).build();
I am getting the exception java.lang.IllegalStateException: No suitable default ClientHttpConnector found. The explanation I get on the internet for that , is to include reactor-netty-http and I was able to get past this issue when i included that in the POM. But I don't think that is the right solution here because I need the mockserver to respond to the webclient request and it is not. Has anyone dealt with this issue before or am I doing this wrong?
Here is the code snippet:
public RequestResponsePact pactMethod(PactDslWithProvider builder) {
Map<String, String> headers = new HashMap<>();
headers.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
return builder.given("Consumer request")
.uponReceiving(" getResource call")
.path("/path")
.method("GET")
.willRespondWith()
.status(200)
.headers(headers)
.body(RESPONSE_JSON).toPact();
}
#Test
#PactTestFor(pactMethod = "pactMethod", port = "9999")
public void consumerTest(MockServer mockServer) {
WebClient webClient = WebClient.builder().baseUrl(mockServer.getUrl()).build();
ConsumerServiceClient consumerServiceClient = new ConsumerServiceClient(webClient);
Mono<Data> data = consumerServiceClient.getData();
StepVerifier.create(data)
.assertNext(resp -> {
try {
Value value = resp.getValue();
Assertions.assertFalse( value.isEmpty());
} catch (Exception e) {
log.error("Unable to convert response to Value", e);
Assertions.fail();
}
}).expectComplete()
.verify();
}
The webclient call:
webClient.get()
.uri("/path")
.retrieve()
.onStatus(status -> status == HttpStatus.NOT_FOUND,
res -> Mono.error(new RunTimeException()))
.bodyToMono(clazz);

How to get response from DHL Api to browser

i have problem with api from dhl, i create GET api from dhl, when print in console, result will print, but when using browser i got response like this :
com.squareup.okhttp.internal.http.RealResponseBody#68bd3d26
this my code :
#RequestMapping("/getData")
public String getAcc() throws IOException
{
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/json");
HttpUrl httpUrl = new HttpUrl.Builder()
.scheme("https")
.host("api-eu.dhl.com")
.addPathSegment("track")
.addPathSegment("shipments")
.addQueryParameter("trackingNumber", "cencored")
.addQueryParameter("service", "express")
.build();
Request request = new Request.Builder()
.addHeader("content-type", "application/json")
.addHeader("Connection", "close")
.addHeader("DHL-API-Key", "cencored")
.addHeader("ConsumerKey", "cencored")
.addHeader("ConsumerSecret", "cencored")
.removeHeader("Content-Encoding")
.removeHeader("Content-Length")
.url(httpUrl) // <- Finally put httpUrl in here
.build();
response = client.newCall(request).execute();
System.out.println(response.body().string());
return this.response.body().toString();
}
solved...
this is weird, but work for me.
so we can't call "response.body().string();" twice.
This is the correctly way to consume a soap webservice with spring boot: https://spring.io/guides/gs/consuming-web-service/
Follow this tutorial and it works fine.

Notify browser download has started immediately with DeferredResult

I have a Spring boot app with #RestController returning DeferredResult, holding "application/pdf" byte[] (from a service I don't control). I want to notify the browser immediately that the download has started, to do this I flush the output stream with response header information.
My code shown below, works with Tomcat (locally & WebLogic) but not Tomcat on Azure Web App. The former shows pdf download in-progress in Chrome's status bar, the latter gives nothing until DeferredResult completes.
Is there a more reliable way to notify the browser of a download than flushing the response header?
Could it be teh code is fine and its Azure preventing the flush being sent to the client? Any help gratefully received.
#RequestMapping(value= DOWNLOAD_BASE_LINK + "/{documentType}/{correlationId}/*", method= RequestMethod.GET, produces=MediaType.APPLICATION_PDF_VALUE)
public DeferredResult<ResponseEntity<?>> download(#PathVariable final PaymentDocumentService.DocumentType documentType,
#PathVariable final String correlationId,
final HttpServletResponse resp,
final HttpServletRequest req) {
LOGGER.debug("Is asyncSupported: [{}] - must be true for document download functionality", req.isAsyncSupported());
LOGGER.info("Searching for documentType [{}] with correlationId [{}]", documentType, correlationId);
final ResponseEntity timeoutResponseEntity = new ResponseEntity(HttpStatus.NOT_FOUND);
final long startTime = System.currentTimeMillis();
final DeferredResult<ResponseEntity<?>> deferredResult = new DeferredResult<>(documentServiceTimeout, timeoutResponseEntity);
final String documentFileName = paymentDocumentService.getDocumentFileName(documentType);
resp.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + documentFileName + "\"");
resp.setContentType(MediaType.APPLICATION_PDF_VALUE);
//Give the browser the header data so it can show the download as started
final OutputStream outputStream;
try {
outputStream = resp.getOutputStream();
outputStream.flush();
} catch (IOException e) {
LOGGER.error("Could not get or flush outputStream");
deferredResult.setResult(new ResponseEntity(HttpStatus.SERVICE_UNAVAILABLE));
return deferredResult;
}
ListenableFuture<DocumentData> futureDocumentData = paymentDocumentService.getDocument(documentType, correlationId);
futureDocumentData.addCallback(new ListenableFutureCallback<DocumentData>() {
#Override
public void onSuccess(DocumentData documentData) {
LOGGER.debug("Start onSuccess: documentData received");
deferredResult.setResult(new ResponseEntity<>(documentData.getBytes(), HttpStatus.OK));
LOGGER.info("End onSuccess: returning deferredResult [{}] (File download time={}ms", deferredResult, System.currentTimeMillis() - startTime);
}
#Override
public void onFailure(Throwable ex) {
LOGGER.error("Start onFailure: documentData type[{}] correlationId[{}] failed", documentType, correlationId, ex);
deferredResult.setResult(new ResponseEntity(HttpStatus.SERVICE_UNAVAILABLE));
LOGGER.error("End onFailure: returning deferredResult [{}]", deferredResult);
}
});
return deferredResult;
}
The question above "Could it be the code is fine and its Azure preventing the flush being sent to the client?" is partly correct. Though not Azure, its actually the IIS web server buffering the response before sending it.
Here is the configuration to not buffer (responseBufferLimit zero) which solved my problem:
<handlers>
<add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" responseBufferLimit="0"/>
</handlers>
Reference: https://learn.microsoft.com/en-us/iis/configuration/system.webserver/handlers/add

spring : get response as Multipart File from REST WebService

I am creating POC for RESTFUL Web service using Spring 4.0. Requirement is to receive MultipartFile as Response from REST WEB-Service.
REST Service Controller
#RequestMapping(value="/getcontent/file", method=RequestMapping.post)
public MultipartFile getMultipartAsFileAsObject() {
File file = new File("src/test/resources/input.docx");
FileInputStream input = new FileInputStream(file);
MultipartFile multipartFile = new MockMultipartFile("file",file.getName(),
"application/docx", IOUtils.toByteArray(input));
return multipartFile
}
I call this service using third party Clients and Apache Http Client as well. kindly have a look on output.
Using Third party REST client ie. Postman
output looks like Json -
{
"name" : "file",
"originalfilename" : "sample.docx",
"contentType" : "application/docx",
"content" : [
82,
101,
97,
100,
101,
32,
32,
.
.
.
.
.
]
}
Apache HTTP Client Sample code
private static void executeClient() {
HttpClient client = new DefaultHttpClient();
HttpPost postReqeust = new HttpPost(SERVER_URI);
try{
// Set Various Attributes
HttpResponse response = client.execute(postReqeust) ;
//Verify response if any
if (response != null)
{
InputStream inputStream = response.getEntity().getContent();
byte[] buffer = new byte[inputStream.available()];
inputStream.read(buffer);
OutputStream outputStream = new FileOutputStream
(new File("src/main/resource/sample.docx"));
outputStream.write(buffer);
outputStream.flush();
outputStream.close();
}
}
catch(Exception ex){
ex.printStackTrace();
}
Output of Apache Http client
file is getting Created but It is empty. (0 bytes).
I found some interesting answers from multiple stackoverflow questions.
Links are given below
file downloading in restful web services
what's the correct way to send a file from REST web service to client?
For Sending single file : (copied from above sources)
#GET
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response getFile() {
File file = ... // Initialize this to the File path you want to serve.
return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)
.header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"" ) //optional
.build();
}
For Sending Zip file : (copied from above sources)
1) Approach First :
You can use above method to send any file / Zip.
private static final String FILE_PATH = "d:\\Test2.zip";
#GET
#Path("/get")
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response getFile() {
File file = new File(FILE_PATH);
ResponseBuilder response = Response.ok((Object) file);
response.header("Content-Disposition", "attachment; filename=newfile.zip");
return response.build();
}
2) Approach Second :
#GET
#Path("/get")
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public StreamingOutput helloWorldZip() throws Exception {
return new StreamingOutput(){
#Override
public void write(OutputStream arg0) throws IOException, WebApplicationException {
// TODO Auto-generated method stub
BufferedOutputStream bus = new BufferedOutputStream(arg0);
try {
Thread.currentThread().getContextClassLoader().getResource("");
File file = new File("d:\\Test1.zip");
FileInputStream fizip = new FileInputStream(file);
byte[] buffer2 = IOUtils.toByteArray(fizip);
bus.write(buffer2);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
}

Resources