001package org.hl7.fhir.r4.utils.client; 002 003 004 005 006 007/* 008 Copyright (c) 2011+, HL7, Inc. 009 All rights reserved. 010 011 Redistribution and use in source and binary forms, with or without modification, 012 are permitted provided that the following conditions are met: 013 014 * Redistributions of source code must retain the above copyright notice, this 015 list of conditions and the following disclaimer. 016 * Redistributions in binary form must reproduce the above copyright notice, 017 this list of conditions and the following disclaimer in the documentation 018 and/or other materials provided with the distribution. 019 * Neither the name of HL7 nor the names of its contributors may be used to 020 endorse or promote products derived from this software without specific 021 prior written permission. 022 023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 024 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 025 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 026 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 027 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 028 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 029 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 030 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 031 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 032 POSSIBILITY OF SUCH DAMAGE. 033 034 */ 035 036 037import java.io.ByteArrayOutputStream; 038import java.io.IOException; 039import java.io.InputStream; 040import java.io.OutputStreamWriter; 041import java.io.UnsupportedEncodingException; 042import java.net.HttpURLConnection; 043import java.net.MalformedURLException; 044import java.net.URI; 045import java.net.URLConnection; 046import java.nio.charset.StandardCharsets; 047import java.text.ParseException; 048import java.text.SimpleDateFormat; 049import java.util.ArrayList; 050import java.util.Calendar; 051import java.util.Date; 052import java.util.List; 053import java.util.Locale; 054import java.util.Map; 055 056import org.apache.commons.codec.binary.Base64; 057import org.apache.commons.io.IOUtils; 058import org.apache.commons.lang3.StringUtils; 059import org.apache.http.Header; 060import org.apache.http.HttpEntityEnclosingRequest; 061import org.apache.http.HttpHost; 062import org.apache.http.HttpRequest; 063import org.apache.http.HttpResponse; 064import org.apache.http.client.HttpClient; 065import org.apache.http.client.methods.HttpDelete; 066import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; 067import org.apache.http.client.methods.HttpGet; 068import org.apache.http.client.methods.HttpOptions; 069import org.apache.http.client.methods.HttpPost; 070import org.apache.http.client.methods.HttpPut; 071import org.apache.http.client.methods.HttpUriRequest; 072import org.apache.http.conn.params.ConnRoutePNames; 073import org.apache.http.entity.ByteArrayEntity; 074import org.apache.http.impl.client.DefaultHttpClient; 075import org.apache.http.params.HttpConnectionParams; 076import org.apache.http.params.HttpParams; 077import org.hl7.fhir.r4.formats.IParser; 078import org.hl7.fhir.r4.formats.IParser.OutputStyle; 079import org.hl7.fhir.r4.formats.JsonParser; 080import org.hl7.fhir.r4.formats.XmlParser; 081import org.hl7.fhir.r4.model.Bundle; 082import org.hl7.fhir.r4.model.OperationOutcome; 083import org.hl7.fhir.r4.model.OperationOutcome.IssueSeverity; 084import org.hl7.fhir.r4.model.OperationOutcome.OperationOutcomeIssueComponent; 085import org.hl7.fhir.r4.model.Resource; 086import org.hl7.fhir.r4.model.ResourceType; 087import org.hl7.fhir.r4.utils.ResourceUtilities; 088import org.hl7.fhir.utilities.ToolingClientLogger; 089import org.hl7.fhir.utilities.Utilities; 090 091/** 092 * Helper class handling lower level HTTP transport concerns. 093 * TODO Document methods. 094 * @author Claude Nanjo 095 */ 096public class ClientUtils { 097 098 public static final String DEFAULT_CHARSET = "UTF-8"; 099 public static final String HEADER_LOCATION = "location"; 100 private static boolean debugging = false; 101 public static final int TIMEOUT_SOCKET = 5000; 102 public static final int TIMEOUT_CONNECT = 1000; 103 104 private HttpHost proxy; 105 private int timeout = TIMEOUT_SOCKET; 106 private String username; 107 private String password; 108 private ToolingClientLogger logger; 109 private int retryCount; 110 private HttpClient httpclient; 111 112 public HttpHost getProxy() { 113 return proxy; 114 } 115 116 public void setProxy(HttpHost proxy) { 117 this.proxy = proxy; 118 } 119 120 public int getTimeout() { 121 return timeout; 122 } 123 124 public void setTimeout(int timeout) { 125 this.timeout = timeout; 126 } 127 128 public String getUsername() { 129 return username; 130 } 131 132 public void setUsername(String username) { 133 this.username = username; 134 } 135 136 public String getPassword() { 137 return password; 138 } 139 140 public void setPassword(String password) { 141 this.password = password; 142 } 143 144 public <T extends Resource> ResourceRequest<T> issueOptionsRequest(URI optionsUri, String resourceFormat, String message, int timeout) { 145 HttpOptions options = new HttpOptions(optionsUri); 146 return issueResourceRequest(resourceFormat, options, message, timeout); 147 } 148 149 public <T extends Resource> ResourceRequest<T> issueGetResourceRequest(URI resourceUri, String resourceFormat, String message, int timeout) { 150 HttpGet httpget = new HttpGet(resourceUri); 151 return issueResourceRequest(resourceFormat, httpget, message, timeout); 152 } 153 154 public <T extends Resource> ResourceRequest<T> issuePutRequest(URI resourceUri, byte[] payload, String resourceFormat, List<Header> headers, String message, int timeout) { 155 HttpPut httpPut = new HttpPut(resourceUri); 156 return issueResourceRequest(resourceFormat, httpPut, payload, headers, message, timeout); 157 } 158 159 public <T extends Resource> ResourceRequest<T> issuePutRequest(URI resourceUri, byte[] payload, String resourceFormat, String message, int timeout) { 160 HttpPut httpPut = new HttpPut(resourceUri); 161 return issueResourceRequest(resourceFormat, httpPut, payload, null, message, timeout); 162 } 163 164 public <T extends Resource> ResourceRequest<T> issuePostRequest(URI resourceUri, byte[] payload, String resourceFormat, List<Header> headers, String message, int timeout) { 165 HttpPost httpPost = new HttpPost(resourceUri); 166 return issueResourceRequest(resourceFormat, httpPost, payload, headers, message, timeout); 167 } 168 169 170 public <T extends Resource> ResourceRequest<T> issuePostRequest(URI resourceUri, byte[] payload, String resourceFormat, String message, int timeout) { 171 return issuePostRequest(resourceUri, payload, resourceFormat, null, message, timeout); 172 } 173 174 public Bundle issueGetFeedRequest(URI resourceUri, String resourceFormat) { 175 HttpGet httpget = new HttpGet(resourceUri); 176 configureFhirRequest(httpget, resourceFormat); 177 HttpResponse response = sendRequest(httpget); 178 return unmarshalReference(response, resourceFormat); 179 } 180 181 private void setAuth(HttpRequest httpget) { 182 if (password != null) { 183 try { 184 byte[] b = Base64.encodeBase64((username+":"+password).getBytes("ASCII")); 185 String b64 = new String(b, StandardCharsets.US_ASCII); 186 httpget.setHeader("Authorization", "Basic " + b64); 187 } catch (UnsupportedEncodingException e) { 188 } 189 } 190 } 191 192 public Bundle postBatchRequest(URI resourceUri, byte[] payload, String resourceFormat, String message, int timeout) { 193 HttpPost httpPost = new HttpPost(resourceUri); 194 configureFhirRequest(httpPost, resourceFormat); 195 HttpResponse response = sendPayload(httpPost, payload, proxy, message, timeout); 196 return unmarshalFeed(response, resourceFormat); 197 } 198 199 public boolean issueDeleteRequest(URI resourceUri) { 200 HttpDelete deleteRequest = new HttpDelete(resourceUri); 201 HttpResponse response = sendRequest(deleteRequest); 202 int responseStatusCode = response.getStatusLine().getStatusCode(); 203 boolean deletionSuccessful = false; 204 if(responseStatusCode == 204) { 205 deletionSuccessful = true; 206 } 207 return deletionSuccessful; 208 } 209 210 /*********************************************************** 211 * Request/Response Helper methods 212 ***********************************************************/ 213 214 protected <T extends Resource> ResourceRequest<T> issueResourceRequest(String resourceFormat, HttpUriRequest request, String message, int timeout) { 215 return issueResourceRequest(resourceFormat, request, null, message, timeout); 216 } 217 218 /** 219 * @param resourceFormat 220 * @param options 221 * @return 222 */ 223 protected <T extends Resource> ResourceRequest<T> issueResourceRequest(String resourceFormat, HttpUriRequest request, byte[] payload, String message, int timeout) { 224 return issueResourceRequest(resourceFormat, request, payload, null, message, timeout); 225 } 226 227 /** 228 * @param resourceFormat 229 * @param options 230 * @return 231 */ 232 protected <T extends Resource> ResourceRequest<T> issueResourceRequest(String resourceFormat, HttpUriRequest request, byte[] payload, List<Header> headers, String message, int timeout) { 233 configureFhirRequest(request, resourceFormat, headers); 234 HttpResponse response = null; 235 if(request instanceof HttpEntityEnclosingRequest && payload != null) { 236 response = sendPayload((HttpEntityEnclosingRequestBase)request, payload, proxy, message, timeout); 237 } else if (request instanceof HttpEntityEnclosingRequest && payload == null){ 238 throw new EFhirClientException("PUT and POST requests require a non-null payload"); 239 } else { 240 response = sendRequest(request); 241 } 242 T resource = unmarshalReference(response, resourceFormat); 243 return new ResourceRequest<T>(resource, response.getStatusLine().getStatusCode(), getLocationHeader(response)); 244 } 245 246 247 /** 248 * Method adds required request headers. 249 * TODO handle JSON request as well. 250 * 251 * @param request 252 */ 253 protected void configureFhirRequest(HttpRequest request, String format) { 254 configureFhirRequest(request, format, null); 255 } 256 257 /** 258 * Method adds required request headers. 259 * TODO handle JSON request as well. 260 * 261 * @param request 262 */ 263 protected void configureFhirRequest(HttpRequest request, String format, List<Header> headers) { 264 request.addHeader("User-Agent", "Java FHIR Client for FHIR"); 265 266 if (format != null) { 267 request.addHeader("Accept",format); 268 request.addHeader("Content-Type", format + ";charset=" + DEFAULT_CHARSET); 269 } 270 request.addHeader("Accept-Charset", DEFAULT_CHARSET); 271 if(headers != null) { 272 for(Header header : headers) { 273 request.addHeader(header); 274 } 275 } 276 setAuth(request); 277 } 278 279 /** 280 * Method posts request payload 281 * 282 * @param request 283 * @param payload 284 * @return 285 */ 286 @SuppressWarnings({ "resource", "deprecation" }) 287 protected HttpResponse sendPayload(HttpEntityEnclosingRequestBase request, byte[] payload, HttpHost proxy, String message, int timeout) { 288 HttpResponse response = null; 289 boolean ok = false; 290 long t = System.currentTimeMillis(); 291 int tryCount = 0; 292 while (!ok) { 293 try { 294 tryCount++; 295 if (httpclient == null) { 296 makeClient(proxy); 297 } 298 HttpParams params = httpclient.getParams(); 299 HttpConnectionParams.setSoTimeout(params, timeout < 1 ? this.timeout : timeout * 1000); 300 request.setEntity(new ByteArrayEntity(payload)); 301 log(request); 302 response = httpclient.execute(request); 303 ok = true; 304 } catch(IOException ioe) { 305 System.out.println(ioe.getMessage()+" ("+(System.currentTimeMillis()-t)+"ms / "+Utilities.describeSize(payload.length)+" for "+message+")"); 306 if (tryCount <= retryCount || (tryCount < 3 && ioe instanceof org.apache.http.conn.ConnectTimeoutException)) { 307 ok = false; 308 try { 309 Thread.sleep(100); 310 } catch (InterruptedException e) { 311 } 312 } else { 313 if (tryCount > 1) { 314 System.out.println("Giving up: "+ioe.getMessage()+" (R4 / "+(System.currentTimeMillis()-t)+"ms / "+Utilities.describeSize(payload.length)+" for "+message+")"); 315 } 316 throw new EFhirClientException("Error sending HTTP Post/Put Payload: "+ioe.getMessage(), ioe); 317 } 318 } 319 } 320 return response; 321 } 322 323 @SuppressWarnings("deprecation") 324 public void makeClient(HttpHost proxy) { 325 httpclient = new DefaultHttpClient(); 326 HttpParams params = httpclient.getParams(); 327 HttpConnectionParams.setConnectionTimeout(params, TIMEOUT_CONNECT); 328 HttpConnectionParams.setSoTimeout(params, timeout); 329 HttpConnectionParams.setSoKeepalive(params, true); 330 if(proxy != null) { 331 httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy); 332 } 333 } 334 335 /** 336 * 337 * @param request 338 * @param payload 339 * @return 340 */ 341 protected HttpResponse sendRequest(HttpUriRequest request) { 342 HttpResponse response = null; 343 try { 344 if (httpclient == null) { 345 makeClient(proxy); 346 } 347 response = httpclient.execute(request); 348 } catch(IOException ioe) { 349 if (ClientUtils.debugging ) { 350 ioe.printStackTrace(); 351 } 352 throw new EFhirClientException("Error sending Http Request: "+ioe.getMessage(), ioe); 353 } 354 return response; 355 } 356 357 358 /** 359 * Unmarshals a resource from the response stream. 360 * 361 * @param response 362 * @return 363 */ 364 @SuppressWarnings("unchecked") 365 protected <T extends Resource> T unmarshalReference(HttpResponse response, String format) { 366 T resource = null; 367 OperationOutcome error = null; 368 byte[] cnt = log(response); 369 if (cnt != null) { 370 try { 371 resource = (T)getParser(format).parse(cnt); 372 if (resource instanceof OperationOutcome && hasError((OperationOutcome)resource)) { 373 error = (OperationOutcome) resource; 374 } 375 } catch(IOException ioe) { 376 throw new EFhirClientException("Error reading Http Response: "+ioe.getMessage(), ioe); 377 } catch(Exception e) { 378 throw new EFhirClientException("Error parsing response message: "+e.getMessage(), e); 379 } 380 } 381 if(error != null) { 382 throw new EFhirClientException("Error from server: "+ResourceUtilities.getErrorDescription(error), error); 383 } 384 return resource; 385 } 386 387 /** 388 * Unmarshals Bundle from response stream. 389 * 390 * @param response 391 * @return 392 */ 393 protected Bundle unmarshalFeed(HttpResponse response, String format) { 394 Bundle feed = null; 395 byte[] cnt = log(response); 396 String contentType = response.getHeaders("Content-Type")[0].getValue(); 397 OperationOutcome error = null; 398 try { 399 if (cnt != null) { 400 if(contentType.contains(ResourceFormat.RESOURCE_XML.getHeader()) || contentType.contains("text/xml+fhir")) { 401 Resource rf = getParser(format).parse(cnt); 402 if (rf instanceof Bundle) 403 feed = (Bundle) rf; 404 else if (rf instanceof OperationOutcome && hasError((OperationOutcome) rf)) { 405 error = (OperationOutcome) rf; 406 } else { 407 throw new EFhirClientException("Error reading server response: a resource was returned instead"); 408 } 409 } 410 } 411 } catch(IOException ioe) { 412 throw new EFhirClientException("Error reading Http Response", ioe); 413 } catch(Exception e) { 414 throw new EFhirClientException("Error parsing response message", e); 415 } 416 if(error != null) { 417 throw new EFhirClientException("Error from server: "+ResourceUtilities.getErrorDescription(error), error); 418 } 419 return feed; 420 } 421 422 private boolean hasError(OperationOutcome oo) { 423 for (OperationOutcomeIssueComponent t : oo.getIssue()) 424 if (t.getSeverity() == IssueSeverity.ERROR || t.getSeverity() == IssueSeverity.FATAL) 425 return true; 426 return false; 427 } 428 429 protected String getLocationHeader(HttpResponse response) { 430 String location = null; 431 if(response.getHeaders("location").length > 0) {//TODO Distinguish between both cases if necessary 432 location = response.getHeaders("location")[0].getValue(); 433 } else if(response.getHeaders("content-location").length > 0) { 434 location = response.getHeaders("content-location")[0].getValue(); 435 } 436 return location; 437 } 438 439 440 /***************************************************************** 441 * Client connection methods 442 * ***************************************************************/ 443 444 public HttpURLConnection buildConnection(URI baseServiceUri, String tail) { 445 try { 446 HttpURLConnection client = (HttpURLConnection) baseServiceUri.resolve(tail).toURL().openConnection(); 447 return client; 448 } catch(MalformedURLException mue) { 449 throw new EFhirClientException("Invalid Service URL", mue); 450 } catch(IOException ioe) { 451 throw new EFhirClientException("Unable to establish connection to server: " + baseServiceUri.toString() + tail, ioe); 452 } 453 } 454 455 public HttpURLConnection buildConnection(URI baseServiceUri, ResourceType resourceType, String id) { 456 return buildConnection(baseServiceUri, ResourceAddress.buildRelativePathFromResourceType(resourceType, id)); 457 } 458 459 /****************************************************************** 460 * Other general helper methods 461 * ****************************************************************/ 462 463 464 public <T extends Resource> byte[] getResourceAsByteArray(T resource, boolean pretty, boolean isJson) { 465 ByteArrayOutputStream baos = null; 466 byte[] byteArray = null; 467 try { 468 baos = new ByteArrayOutputStream(); 469 IParser parser = null; 470 if(isJson) { 471 parser = new JsonParser(); 472 } else { 473 parser = new XmlParser(); 474 } 475 parser.setOutputStyle(pretty ? OutputStyle.PRETTY : OutputStyle.NORMAL); 476 parser.compose(baos, resource); 477 baos.close(); 478 byteArray = baos.toByteArray(); 479 baos.close(); 480 } catch (Exception e) { 481 try{ 482 baos.close(); 483 }catch(Exception ex) { 484 throw new EFhirClientException("Error closing output stream", ex); 485 } 486 throw new EFhirClientException("Error converting output stream to byte array", e); 487 } 488 return byteArray; 489 } 490 491 public byte[] getFeedAsByteArray(Bundle feed, boolean pretty, boolean isJson) { 492 ByteArrayOutputStream baos = null; 493 byte[] byteArray = null; 494 try { 495 baos = new ByteArrayOutputStream(); 496 IParser parser = null; 497 if(isJson) { 498 parser = new JsonParser(); 499 } else { 500 parser = new XmlParser(); 501 } 502 parser.setOutputStyle(pretty ? OutputStyle.PRETTY : OutputStyle.NORMAL); 503 parser.compose(baos, feed); 504 baos.close(); 505 byteArray = baos.toByteArray(); 506 baos.close(); 507 } catch (Exception e) { 508 try{ 509 baos.close(); 510 }catch(Exception ex) { 511 throw new EFhirClientException("Error closing output stream", ex); 512 } 513 throw new EFhirClientException("Error converting output stream to byte array", e); 514 } 515 return byteArray; 516 } 517 518 public Calendar getLastModifiedResponseHeaderAsCalendarObject(URLConnection serverConnection) { 519 String dateTime = null; 520 try { 521 dateTime = serverConnection.getHeaderField("Last-Modified"); 522 SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", new Locale("en", "US")); 523 Date lastModifiedTimestamp = format.parse(dateTime); 524 Calendar calendar=Calendar.getInstance(); 525 calendar.setTime(lastModifiedTimestamp); 526 return calendar; 527 } catch(ParseException pe) { 528 throw new EFhirClientException("Error parsing Last-Modified response header " + dateTime, pe); 529 } 530 } 531 532 protected IParser getParser(String format) { 533 if(StringUtils.isBlank(format)) { 534 format = ResourceFormat.RESOURCE_XML.getHeader(); 535 } 536 if(format.equalsIgnoreCase("json") || format.equalsIgnoreCase(ResourceFormat.RESOURCE_JSON.getHeader()) || format.equalsIgnoreCase(ResourceFormat.RESOURCE_JSON.getHeader())) { 537 return new JsonParser(); 538 } else if(format.equalsIgnoreCase("xml") || format.equalsIgnoreCase(ResourceFormat.RESOURCE_XML.getHeader()) || format.equalsIgnoreCase(ResourceFormat.RESOURCE_XML.getHeader())) { 539 return new XmlParser(); 540 } else { 541 throw new EFhirClientException("Invalid format: " + format); 542 } 543 } 544 545 public Bundle issuePostFeedRequest(URI resourceUri, Map<String, String> parameters, String resourceName, Resource resource, String resourceFormat) throws IOException { 546 HttpPost httppost = new HttpPost(resourceUri); 547 String boundary = "----WebKitFormBoundarykbMUo6H8QaUnYtRy"; 548 httppost.addHeader("Content-Type", "multipart/form-data; boundary="+boundary); 549 httppost.addHeader("Accept", resourceFormat); 550 configureFhirRequest(httppost, null); 551 HttpResponse response = sendPayload(httppost, encodeFormSubmission(parameters, resourceName, resource, boundary)); 552 return unmarshalFeed(response, resourceFormat); 553 } 554 555 private byte[] encodeFormSubmission(Map<String, String> parameters, String resourceName, Resource resource, String boundary) throws IOException { 556 ByteArrayOutputStream b = new ByteArrayOutputStream(); 557 OutputStreamWriter w = new OutputStreamWriter(b, "UTF-8"); 558 for (String name : parameters.keySet()) { 559 w.write("--"); 560 w.write(boundary); 561 w.write("\r\nContent-Disposition: form-data; name=\""+name+"\"\r\n\r\n"); 562 w.write(parameters.get(name)+"\r\n"); 563 } 564 w.write("--"); 565 w.write(boundary); 566 w.write("\r\nContent-Disposition: form-data; name=\""+resourceName+"\"\r\n\r\n"); 567 w.close(); 568 JsonParser json = new JsonParser(); 569 json.setOutputStyle(OutputStyle.NORMAL); 570 json.compose(b, resource); 571 b.close(); 572 w = new OutputStreamWriter(b, "UTF-8"); 573 w.write("\r\n--"); 574 w.write(boundary); 575 w.write("--"); 576 w.close(); 577 return b.toByteArray(); 578 } 579 580 /** 581 * Method posts request payload 582 * 583 * @param request 584 * @param payload 585 * @return 586 */ 587 protected HttpResponse sendPayload(HttpEntityEnclosingRequestBase request, byte[] payload) { 588 HttpResponse response = null; 589 try { 590 log(request); 591 if (httpclient == null) { 592 makeClient(proxy); 593 } 594 request.setEntity(new ByteArrayEntity(payload)); 595 response = httpclient.execute(request); 596 log(response); 597 } catch(IOException ioe) { 598 throw new EFhirClientException("Error sending HTTP Post/Put Payload: "+ioe.getMessage(), ioe); 599 } 600 return response; 601 } 602 603 private void log(HttpUriRequest request) { 604 if (logger != null) { 605 List<String> headers = new ArrayList<>(); 606 for (Header h : request.getAllHeaders()) { 607 headers.add(h.toString()); 608 } 609 logger.logRequest(request.getMethod(), request.getURI().toString(), headers, null); 610 } 611 } 612 private void log(HttpEntityEnclosingRequestBase request) { 613 if (logger != null) { 614 List<String> headers = new ArrayList<>(); 615 for (Header h : request.getAllHeaders()) { 616 headers.add(h.toString()); 617 } 618 byte[] cnt = null; 619 InputStream s; 620 try { 621 s = request.getEntity().getContent(); 622 cnt = IOUtils.toByteArray(s); 623 s.close(); 624 } catch (Exception e) { 625 } 626 logger.logRequest(request.getMethod(), request.getURI().toString(), headers, cnt); 627 } 628 } 629 630 private byte[] log(HttpResponse response) { 631 byte[] cnt = null; 632 try { 633 InputStream s = response.getEntity().getContent(); 634 cnt = IOUtils.toByteArray(s); 635 s.close(); 636 } catch (Exception e) { 637 } 638 if (logger != null) { 639 List<String> headers = new ArrayList<>(); 640 for (Header h : response.getAllHeaders()) { 641 headers.add(h.toString()); 642 } 643 logger.logResponse(response.getStatusLine().toString(), headers, cnt); 644 } 645 return cnt; 646 } 647 648 public ToolingClientLogger getLogger() { 649 return logger; 650 } 651 652 public void setLogger(ToolingClientLogger logger) { 653 this.logger = logger; 654 } 655 656 657 /** 658 * Used for debugging 659 * 660 * @param instream 661 * @return 662 */ 663 protected String writeInputStreamAsString(InputStream instream) { 664 String value = null; 665 try { 666 value = IOUtils.toString(instream, "UTF-8"); 667 System.out.println(value); 668 669 } catch(IOException ioe) { 670 //Do nothing 671 } 672 return value; 673 } 674 675 public int getRetryCount() { 676 return retryCount; 677 } 678 679 public void setRetryCount(int retryCount) { 680 this.retryCount = retryCount; 681 } 682 683 684}