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