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