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