001package org.hl7.fhir.dstu2.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.dstu2.formats.IParser; 078import org.hl7.fhir.dstu2.formats.IParser.OutputStyle; 079import org.hl7.fhir.dstu2.formats.JsonParser; 080import org.hl7.fhir.dstu2.formats.XmlParser; 081import org.hl7.fhir.dstu2.model.Bundle; 082import org.hl7.fhir.dstu2.model.OperationOutcome; 083import org.hl7.fhir.dstu2.model.OperationOutcome.IssueSeverity; 084import org.hl7.fhir.dstu2.model.OperationOutcome.OperationOutcomeIssueComponent; 085import org.hl7.fhir.dstu2.model.Resource; 086import org.hl7.fhir.dstu2.model.ResourceType; 087import org.hl7.fhir.dstu2.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 102 private HttpHost proxy; 103 private int timeout = 5000; 104 private String username; 105 private String password; 106 private ToolingClientLogger logger; 107 private int retryCount; 108 109 public HttpHost getProxy() { 110 return proxy; 111 } 112 113 public void setProxy(HttpHost proxy) { 114 this.proxy = proxy; 115 } 116 117 public int getTimeout() { 118 return timeout; 119 } 120 121 public void setTimeout(int timeout) { 122 this.timeout = timeout; 123 } 124 125 public String getUsername() { 126 return username; 127 } 128 129 public void setUsername(String username) { 130 this.username = username; 131 } 132 133 public String getPassword() { 134 return password; 135 } 136 137 public void setPassword(String password) { 138 this.password = password; 139 } 140 141 public <T extends Resource> ResourceRequest<T> issueOptionsRequest(URI optionsUri, String resourceFormat, int timeoutLoading) { 142 HttpOptions options = new HttpOptions(optionsUri); 143 return issueResourceRequest(resourceFormat, options, timeoutLoading); 144 } 145 146 public <T extends Resource> ResourceRequest<T> issueGetResourceRequest(URI resourceUri, String resourceFormat, int timeoutLoading) { 147 HttpGet httpget = new HttpGet(resourceUri); 148 return issueResourceRequest(resourceFormat, httpget, timeoutLoading); 149 } 150 151 public <T extends Resource> ResourceRequest<T> issuePutRequest(URI resourceUri, byte[] payload, String resourceFormat, List<Header> headers, int timeoutLoading) { 152 HttpPut httpPut = new HttpPut(resourceUri); 153 return issueResourceRequest(resourceFormat, httpPut, payload, headers, timeoutLoading); 154 } 155 156 public <T extends Resource> ResourceRequest<T> issuePutRequest(URI resourceUri, byte[] payload, String resourceFormat, int timeoutLoading) { 157 HttpPut httpPut = new HttpPut(resourceUri); 158 return issueResourceRequest(resourceFormat, httpPut, payload, null, timeoutLoading); 159 } 160 161 public <T extends Resource> ResourceRequest<T> issuePostRequest(URI resourceUri, byte[] payload, String resourceFormat, List<Header> headers, int timeoutLoading) { 162 HttpPost httpPost = new HttpPost(resourceUri); 163 return issueResourceRequest(resourceFormat, httpPost, payload, headers, timeoutLoading); 164 } 165 166 167 public <T extends Resource> ResourceRequest<T> issuePostRequest(URI resourceUri, byte[] payload, String resourceFormat, int timeoutLoading) { 168 return issuePostRequest(resourceUri, payload, resourceFormat, null, timeoutLoading); 169 } 170 171 public Bundle issueGetFeedRequest(URI resourceUri, String resourceFormat) { 172 HttpGet httpget = new HttpGet(resourceUri); 173 configureFhirRequest(httpget, resourceFormat); 174 HttpResponse response = sendRequest(httpget); 175 return unmarshalReference(response, resourceFormat); 176 } 177 178 private void setAuth(HttpRequest httpget) { 179 if (password != null) { 180 try { 181 byte[] b = Base64.encodeBase64((username+":"+password).getBytes("ASCII")); 182 String b64 = new String(b, StandardCharsets.US_ASCII); 183 httpget.setHeader("Authorization", "Basic " + b64); 184 } catch (UnsupportedEncodingException e) { 185 } 186 } 187 } 188 189 public Bundle postBatchRequest(URI resourceUri, byte[] payload, String resourceFormat, int timeoutLoading) { 190 HttpPost httpPost = new HttpPost(resourceUri); 191 configureFhirRequest(httpPost, resourceFormat); 192 HttpResponse response = sendPayload(httpPost, payload, proxy, timeoutLoading); 193 return unmarshalFeed(response, resourceFormat); 194 } 195 196 public boolean issueDeleteRequest(URI resourceUri) { 197 HttpDelete deleteRequest = new HttpDelete(resourceUri); 198 HttpResponse response = sendRequest(deleteRequest); 199 int responseStatusCode = response.getStatusLine().getStatusCode(); 200 boolean deletionSuccessful = false; 201 if(responseStatusCode == 204) { 202 deletionSuccessful = true; 203 } 204 return deletionSuccessful; 205 } 206 207 /*********************************************************** 208 * Request/Response Helper methods 209 ***********************************************************/ 210 211 protected <T extends Resource> ResourceRequest<T> issueResourceRequest(String resourceFormat, HttpUriRequest request, int timeoutLoading) { 212 return issueResourceRequest(resourceFormat, request, null, timeoutLoading); 213 } 214 215 /** 216 * @param resourceFormat 217 * @param options 218 * @return 219 */ 220 protected <T extends Resource> ResourceRequest<T> issueResourceRequest(String resourceFormat, HttpUriRequest request, byte[] payload, int timeoutLoading) { 221 return issueResourceRequest(resourceFormat, request, payload, null, timeoutLoading); 222 } 223 224 /** 225 * @param resourceFormat 226 * @param options 227 * @return 228 */ 229 protected <T extends Resource> ResourceRequest<T> issueResourceRequest(String resourceFormat, HttpUriRequest request, byte[] payload, List<Header> headers, int timeoutLoading) { 230 configureFhirRequest(request, resourceFormat, headers); 231 HttpResponse response = null; 232 if(request instanceof HttpEntityEnclosingRequest && payload != null) { 233 response = sendPayload((HttpEntityEnclosingRequestBase)request, payload, proxy, timeoutLoading); 234 } else if (request instanceof HttpEntityEnclosingRequest && payload == null){ 235 throw new EFhirClientException("PUT and POST requests require a non-null payload"); 236 } else { 237 response = sendRequest(request); 238 } 239 T resource = unmarshalReference(response, resourceFormat); 240 return new ResourceRequest<T>(resource, response.getStatusLine().getStatusCode(), getLocationHeader(response)); 241 } 242 243 244 /** 245 * Method adds required request headers. 246 * TODO handle JSON request as well. 247 * 248 * @param request 249 */ 250 protected void configureFhirRequest(HttpRequest request, String format) { 251 configureFhirRequest(request, format, null); 252 } 253 254 /** 255 * Method adds required request headers. 256 * TODO handle JSON request as well. 257 * 258 * @param request 259 */ 260 protected void configureFhirRequest(HttpRequest request, String format, List<Header> headers) { 261 request.addHeader("User-Agent", "Java FHIR Client for FHIR"); 262 263 if (format != null) { 264 request.addHeader("Accept",format); 265 request.addHeader("Content-Type", format + ";charset=" + DEFAULT_CHARSET); 266 } 267 request.addHeader("Accept-Charset", DEFAULT_CHARSET); 268 if(headers != null) { 269 for(Header header : headers) { 270 request.addHeader(header); 271 } 272 } 273 setAuth(request); 274 } 275 276 /** 277 * Method posts request payload 278 * 279 * @param request 280 * @param payload 281 * @return 282 */ 283 @SuppressWarnings({ "resource", "deprecation" }) 284 protected HttpResponse sendPayload(HttpEntityEnclosingRequestBase request, byte[] payload, HttpHost proxy, int timeoutLoading) { 285 HttpResponse response = null; 286 boolean ok = false; 287 long t = System.currentTimeMillis(); 288 int tryCount = 0; 289 while (!ok) { 290 try { 291 tryCount++; 292 HttpClient httpclient = new DefaultHttpClient(); 293 HttpParams params = httpclient.getParams(); 294 HttpConnectionParams.setConnectionTimeout(params, timeout); 295 HttpConnectionParams.setSoTimeout(params, timeout * timeoutLoading); 296 297 if(proxy != null) { 298 httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy); 299 } 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)+")"); 306 if (tryCount <= retryCount || (tryCount < 3 && ioe instanceof org.apache.http.conn.ConnectTimeoutException)) { 307 ok = false; 308 } else { 309 throw new EFhirClientException("Error sending HTTP Post/Put Payload: "+ioe.getMessage(), ioe); 310 } 311 } 312 } 313 return response; 314 } 315 316 /** 317 * 318 * @param request 319 * @param payload 320 * @return 321 */ 322 protected HttpResponse sendRequest(HttpUriRequest request) { 323 HttpResponse response = null; 324 try { 325 HttpClient httpclient = new DefaultHttpClient(); 326 log(request); 327 HttpParams params = httpclient.getParams(); 328 HttpConnectionParams.setConnectionTimeout(params, timeout); 329 HttpConnectionParams.setSoTimeout(params, timeout); 330 if(proxy != null) { 331 httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy); 332 } 333 response = httpclient.execute(request); 334 } catch(IOException ioe) { 335 if (ClientUtils.debugging ) { 336 ioe.printStackTrace(); 337 } 338 throw new EFhirClientException("Error sending Http Request: "+ioe.getMessage(), ioe); 339 } 340 return response; 341 } 342 343 /** 344 * Unmarshals a resource from the response stream. 345 * 346 * @param response 347 * @return 348 */ 349 @SuppressWarnings("unchecked") 350 protected <T extends Resource> T unmarshalReference(HttpResponse response, String format) { 351 T resource = null; 352 OperationOutcome error = null; 353 byte[] cnt = log(response); 354 if (cnt != null) { 355 try { 356 resource = (T)getParser(format).parse(cnt); 357 if (resource instanceof OperationOutcome && hasError((OperationOutcome)resource)) { 358 error = (OperationOutcome) resource; 359 } 360 } catch(IOException ioe) { 361 throw new EFhirClientException("Error reading Http Response: "+ioe.getMessage(), ioe); 362 } catch(Exception e) { 363 throw new EFhirClientException("Error parsing response message: "+e.getMessage(), e); 364 } 365 } 366 if(error != null) { 367 throw new EFhirClientException("Error from server: "+ResourceUtilities.getErrorDescription(error), error); 368 } 369 return resource; 370 } 371 372 /** 373 * Unmarshals Bundle from response stream. 374 * 375 * @param response 376 * @return 377 */ 378 protected Bundle unmarshalFeed(HttpResponse response, String format) { 379 Bundle feed = null; 380 byte[] cnt = log(response); 381 String contentType = response.getHeaders("Content-Type")[0].getValue(); 382 OperationOutcome error = null; 383 try { 384 if (cnt != null) { 385 if(contentType.contains(ResourceFormat.RESOURCE_XML.getHeader()) || contentType.contains("text/xml+fhir")) { 386 Resource rf = getParser(format).parse(cnt); 387 if (rf instanceof Bundle) 388 feed = (Bundle) rf; 389 else if (rf instanceof OperationOutcome && hasError((OperationOutcome) rf)) { 390 error = (OperationOutcome) rf; 391 } else { 392 throw new EFhirClientException("Error reading server response: a resource was returned instead"); 393 } 394 } 395 } 396 } catch(IOException ioe) { 397 throw new EFhirClientException("Error reading Http Response", ioe); 398 } catch(Exception e) { 399 throw new EFhirClientException("Error parsing response message", e); 400 } 401 if(error != null) { 402 throw new EFhirClientException("Error from server: "+ResourceUtilities.getErrorDescription(error), error); 403 } 404 return feed; 405 } 406 407 private boolean hasError(OperationOutcome oo) { 408 for (OperationOutcomeIssueComponent t : oo.getIssue()) 409 if (t.getSeverity() == IssueSeverity.ERROR || t.getSeverity() == IssueSeverity.FATAL) 410 return true; 411 return false; 412 } 413 414 protected String getLocationHeader(HttpResponse response) { 415 String location = null; 416 if(response.getHeaders("location").length > 0) {//TODO Distinguish between both cases if necessary 417 location = response.getHeaders("location")[0].getValue(); 418 } else if(response.getHeaders("content-location").length > 0) { 419 location = response.getHeaders("content-location")[0].getValue(); 420 } 421 return location; 422 } 423 424 425 /***************************************************************** 426 * Client connection methods 427 * ***************************************************************/ 428 429 public HttpURLConnection buildConnection(URI baseServiceUri, String tail) { 430 try { 431 HttpURLConnection client = (HttpURLConnection) baseServiceUri.resolve(tail).toURL().openConnection(); 432 return client; 433 } catch(MalformedURLException mue) { 434 throw new EFhirClientException("Invalid Service URL", mue); 435 } catch(IOException ioe) { 436 throw new EFhirClientException("Unable to establish connection to server: " + baseServiceUri.toString() + tail, ioe); 437 } 438 } 439 440 public HttpURLConnection buildConnection(URI baseServiceUri, ResourceType resourceType, String id) { 441 return buildConnection(baseServiceUri, ResourceAddress.buildRelativePathFromResourceType(resourceType, id)); 442 } 443 444 /****************************************************************** 445 * Other general helper methods 446 * ****************************************************************/ 447 448 449 public <T extends Resource> byte[] getResourceAsByteArray(T resource, boolean pretty, boolean isJson) { 450 ByteArrayOutputStream baos = null; 451 byte[] byteArray = null; 452 try { 453 baos = new ByteArrayOutputStream(); 454 IParser parser = null; 455 if(isJson) { 456 parser = new JsonParser(); 457 } else { 458 parser = new XmlParser(); 459 } 460 parser.setOutputStyle(pretty ? OutputStyle.PRETTY : OutputStyle.NORMAL); 461 parser.compose(baos, resource); 462 baos.close(); 463 byteArray = baos.toByteArray(); 464 baos.close(); 465 } catch (Exception e) { 466 try{ 467 baos.close(); 468 }catch(Exception ex) { 469 throw new EFhirClientException("Error closing output stream", ex); 470 } 471 throw new EFhirClientException("Error converting output stream to byte array", e); 472 } 473 return byteArray; 474 } 475 476 public byte[] getFeedAsByteArray(Bundle feed, boolean pretty, boolean isJson) { 477 ByteArrayOutputStream baos = null; 478 byte[] byteArray = null; 479 try { 480 baos = new ByteArrayOutputStream(); 481 IParser parser = null; 482 if(isJson) { 483 parser = new JsonParser(); 484 } else { 485 parser = new XmlParser(); 486 } 487 parser.setOutputStyle(pretty ? OutputStyle.PRETTY : OutputStyle.NORMAL); 488 parser.compose(baos, feed); 489 baos.close(); 490 byteArray = baos.toByteArray(); 491 baos.close(); 492 } catch (Exception e) { 493 try{ 494 baos.close(); 495 }catch(Exception ex) { 496 throw new EFhirClientException("Error closing output stream", ex); 497 } 498 throw new EFhirClientException("Error converting output stream to byte array", e); 499 } 500 return byteArray; 501 } 502 503 public Calendar getLastModifiedResponseHeaderAsCalendarObject(URLConnection serverConnection) { 504 String dateTime = null; 505 try { 506 dateTime = serverConnection.getHeaderField("Last-Modified"); 507 SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", new Locale("en", "US")); 508 Date lastModifiedTimestamp = format.parse(dateTime); 509 Calendar calendar=Calendar.getInstance(); 510 calendar.setTime(lastModifiedTimestamp); 511 return calendar; 512 } catch(ParseException pe) { 513 throw new EFhirClientException("Error parsing Last-Modified response header " + dateTime, pe); 514 } 515 } 516 517 protected IParser getParser(String format) { 518 if(StringUtils.isBlank(format)) { 519 format = ResourceFormat.RESOURCE_XML.getHeader(); 520 } 521 if(format.equalsIgnoreCase("json") || format.equalsIgnoreCase(ResourceFormat.RESOURCE_JSON.getHeader()) || format.equalsIgnoreCase(ResourceFormat.RESOURCE_JSON.getHeader())) { 522 return new JsonParser(); 523 } else if(format.equalsIgnoreCase("xml") || format.equalsIgnoreCase(ResourceFormat.RESOURCE_XML.getHeader()) || format.equalsIgnoreCase(ResourceFormat.RESOURCE_XML.getHeader())) { 524 return new XmlParser(); 525 } else { 526 throw new EFhirClientException("Invalid format: " + format); 527 } 528 } 529 530 public Bundle issuePostFeedRequest(URI resourceUri, Map<String, String> parameters, String resourceName, Resource resource, String resourceFormat) throws IOException { 531 HttpPost httppost = new HttpPost(resourceUri); 532 String boundary = "----WebKitFormBoundarykbMUo6H8QaUnYtRy"; 533 httppost.addHeader("Content-Type", "multipart/form-data; boundary="+boundary); 534 httppost.addHeader("Accept", resourceFormat); 535 configureFhirRequest(httppost, null); 536 HttpResponse response = sendPayload(httppost, encodeFormSubmission(parameters, resourceName, resource, boundary)); 537 return unmarshalFeed(response, resourceFormat); 538 } 539 540 private byte[] encodeFormSubmission(Map<String, String> parameters, String resourceName, Resource resource, String boundary) throws IOException { 541 ByteArrayOutputStream b = new ByteArrayOutputStream(); 542 OutputStreamWriter w = new OutputStreamWriter(b, "UTF-8"); 543 for (String name : parameters.keySet()) { 544 w.write("--"); 545 w.write(boundary); 546 w.write("\r\nContent-Disposition: form-data; name=\""+name+"\"\r\n\r\n"); 547 w.write(parameters.get(name)+"\r\n"); 548 } 549 w.write("--"); 550 w.write(boundary); 551 w.write("\r\nContent-Disposition: form-data; name=\""+resourceName+"\"\r\n\r\n"); 552 w.close(); 553 JsonParser json = new JsonParser(); 554 json.setOutputStyle(OutputStyle.NORMAL); 555 json.compose(b, resource); 556 b.close(); 557 w = new OutputStreamWriter(b, "UTF-8"); 558 w.write("\r\n--"); 559 w.write(boundary); 560 w.write("--"); 561 w.close(); 562 return b.toByteArray(); 563 } 564 565 /** 566 * Method posts request payload 567 * 568 * @param request 569 * @param payload 570 * @return 571 */ 572 protected HttpResponse sendPayload(HttpEntityEnclosingRequestBase request, byte[] payload) { 573 HttpResponse response = null; 574 try { 575 log(request); 576 HttpClient httpclient = new DefaultHttpClient(); 577 request.setEntity(new ByteArrayEntity(payload)); 578 response = httpclient.execute(request); 579 log(response); 580 } catch(IOException ioe) { 581 throw new EFhirClientException("Error sending HTTP Post/Put Payload: "+ioe.getMessage(), ioe); 582 } 583 return response; 584 } 585 586 private void log(HttpUriRequest request) { 587 if (logger != null) { 588 List<String> headers = new ArrayList<>(); 589 for (Header h : request.getAllHeaders()) { 590 headers.add(h.toString()); 591 } 592 logger.logRequest(request.getMethod(), request.getURI().toString(), headers, null); 593 } 594 } 595 private void log(HttpEntityEnclosingRequestBase request) { 596 if (logger != null) { 597 List<String> headers = new ArrayList<>(); 598 for (Header h : request.getAllHeaders()) { 599 headers.add(h.toString()); 600 } 601 byte[] cnt = null; 602 InputStream s; 603 try { 604 s = request.getEntity().getContent(); 605 cnt = IOUtils.toByteArray(s); 606 s.close(); 607 } catch (Exception e) { 608 } 609 logger.logRequest(request.getMethod(), request.getURI().toString(), headers, cnt); 610 } 611 } 612 613 private byte[] log(HttpResponse response) { 614 byte[] cnt = null; 615 try { 616 InputStream s = response.getEntity().getContent(); 617 cnt = IOUtils.toByteArray(s); 618 s.close(); 619 } catch (Exception e) { 620 } 621 if (logger != null) { 622 List<String> headers = new ArrayList<>(); 623 for (Header h : response.getAllHeaders()) { 624 headers.add(h.toString()); 625 } 626 logger.logResponse(response.getStatusLine().toString(), headers, cnt); 627 } 628 return cnt; 629 } 630 631 public ToolingClientLogger getLogger() { 632 return logger; 633 } 634 635 public void setLogger(ToolingClientLogger logger) { 636 this.logger = logger; 637 } 638 639 640 /** 641 * Used for debugging 642 * 643 * @param instream 644 * @return 645 */ 646 protected String writeInputStreamAsString(InputStream instream) { 647 String value = null; 648 try { 649 value = IOUtils.toString(instream, "UTF-8"); 650 System.out.println(value); 651 652 } catch(IOException ioe) { 653 //Do nothing 654 } 655 return value; 656 } 657 658 public int getRetryCount() { 659 return retryCount; 660 } 661 662 public void setRetryCount(int retryCount) { 663 this.retryCount = retryCount; 664 } 665 666 667}