001package org.hl7.fhir.r4.utils.client; 002 003 004/* 005 Copyright (c) 2011+, HL7, Inc. 006 All rights reserved. 007 008 Redistribution and use in source and binary forms, with or without modification, 009 are permitted provided that the following conditions are met: 010 011 * Redistributions of source code must retain the above copyright notice, this 012 list of conditions and the following disclaimer. 013 * Redistributions in binary form must reproduce the above copyright notice, 014 this list of conditions and the following disclaimer in the documentation 015 and/or other materials provided with the distribution. 016 * Neither the name of HL7 nor the names of its contributors may be used to 017 endorse or promote products derived from this software without specific 018 prior written permission. 019 020 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 021 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 022 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 023 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 024 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 025 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 026 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 027 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 028 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 029 POSSIBILITY OF SUCH DAMAGE. 030 031*/ 032 033import java.net.URI; 034import java.net.URISyntaxException; 035import java.util.HashMap; 036import java.util.List; 037import java.util.Map; 038 039import org.apache.http.Header; 040import org.apache.http.HttpHost; 041import org.hl7.fhir.r4.model.Bundle; 042import org.hl7.fhir.r4.model.CapabilityStatement; 043import org.hl7.fhir.r4.model.CodeSystem; 044import org.hl7.fhir.r4.model.Coding; 045import org.hl7.fhir.r4.model.ConceptMap; 046import org.hl7.fhir.r4.model.OperationOutcome; 047import org.hl7.fhir.r4.model.Parameters; 048import org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent; 049import org.hl7.fhir.r4.model.PrimitiveType; 050import org.hl7.fhir.r4.model.Resource; 051import org.hl7.fhir.r4.model.StringType; 052import org.hl7.fhir.r4.model.TerminologyCapabilities; 053import org.hl7.fhir.r4.model.ValueSet; 054import org.hl7.fhir.utilities.Utilities; 055 056/** 057 * Very Simple RESTful client. This is purely for use in the standalone 058 * tools jar packages. It doesn't support many features, only what the tools 059 * need. 060 * 061 * To use, initialize class and set base service URI as follows: 062 * 063 * <pre><code> 064 * FHIRSimpleClient fhirClient = new FHIRSimpleClient(); 065 * fhirClient.initialize("http://my.fhir.domain/myServiceRoot"); 066 * </code></pre> 067 * 068 * Default Accept and Content-Type headers are application/fhir+xml and application/fhir+json. 069 * 070 * These can be changed by invoking the following setter functions: 071 * 072 * <pre><code> 073 * setPreferredResourceFormat() 074 * setPreferredFeedFormat() 075 * </code></pre> 076 * 077 * TODO Review all sad paths. 078 * 079 * @author Claude Nanjo 080 * 081 */ 082public class FHIRToolingClient { 083 084 public static final String DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ssK"; 085 public static final String DATE_FORMAT = "yyyy-MM-dd"; 086 public static final String hostKey = "http.proxyHost"; 087 public static final String portKey = "http.proxyPort"; 088 089 private String base; 090 private ResourceAddress resourceAddress; 091 private ResourceFormat preferredResourceFormat; 092 private int maxResultSetSize = -1;//_count 093 private CapabilityStatement capabilities; 094 095 private ClientUtils utils = new ClientUtils(); 096 097 //Pass enpoint for client - URI 098 public FHIRToolingClient(String baseServiceUrl) throws URISyntaxException { 099 preferredResourceFormat = ResourceFormat.RESOURCE_XML; 100 detectProxy(); 101 initialize(baseServiceUrl); 102 } 103 104 public FHIRToolingClient(String baseServiceUrl, String username, String password) throws URISyntaxException { 105 preferredResourceFormat = ResourceFormat.RESOURCE_XML; 106 utils.setUsername(username); 107 utils.setPassword(password); 108 detectProxy(); 109 initialize(baseServiceUrl); 110 } 111 112 public void configureProxy(String proxyHost, int proxyPort) { 113 utils.setProxy(new HttpHost(proxyHost, proxyPort)); 114 } 115 116 public void detectProxy() { 117 String host = System.getenv(hostKey); 118 String port = System.getenv(portKey); 119 120 if(host==null) { 121 host = System.getProperty(hostKey); 122 } 123 124 if(port==null) { 125 port = System.getProperty(portKey); 126 } 127 128 if(host!=null && port!=null) { 129 this.configureProxy(host, Integer.parseInt(port)); 130 } 131 } 132 133 public void initialize(String baseServiceUrl) throws URISyntaxException { 134 base = baseServiceUrl; 135 resourceAddress = new ResourceAddress(baseServiceUrl); 136 this.maxResultSetSize = -1; 137 checkCapabilities(); 138 } 139 140 private void checkCapabilities() { 141 try { 142 capabilities = getCapabilitiesStatementQuick(); 143 } catch (Throwable e) { 144 } 145 } 146 147 public String getPreferredResourceFormat() { 148 return preferredResourceFormat.getHeader(); 149 } 150 151 public void setPreferredResourceFormat(ResourceFormat resourceFormat) { 152 preferredResourceFormat = resourceFormat; 153 } 154 155 public int getMaximumRecordCount() { 156 return maxResultSetSize; 157 } 158 159 public void setMaximumRecordCount(int maxResultSetSize) { 160 this.maxResultSetSize = maxResultSetSize; 161 } 162 163 public TerminologyCapabilities getTerminologyCapabilities() { 164 return (TerminologyCapabilities) utils.issueGetResourceRequest(resourceAddress.resolveMetadataTxCaps(), getPreferredResourceFormat()).getReference(); 165 } 166 167 public CapabilityStatement getCapabilitiesStatement() { 168 CapabilityStatement conformance = null; 169 try { 170 conformance = (CapabilityStatement)utils.issueGetResourceRequest(resourceAddress.resolveMetadataUri(false), getPreferredResourceFormat()).getReference(); 171 } catch(Exception e) { 172 handleException("An error has occurred while trying to fetch the server's conformance statement", e); 173 } 174 return conformance; 175 } 176 177 public CapabilityStatement getCapabilitiesStatementQuick() throws EFhirClientException { 178 if (capabilities != null) 179 return capabilities; 180 try { 181 capabilities = (CapabilityStatement)utils.issueGetResourceRequest(resourceAddress.resolveMetadataUri(true), getPreferredResourceFormat()).getReference(); 182 } catch(Exception e) { 183 handleException("An error has occurred while trying to fetch the server's conformance statement", e); 184 } 185 return capabilities; 186 } 187 188 public <T extends Resource> T read(Class<T> resourceClass, String id) {//TODO Change this to AddressableResource 189 ResourceRequest<T> result = null; 190 try { 191 result = utils.issueGetResourceRequest(resourceAddress.resolveGetUriFromResourceClassAndId(resourceClass, id), getPreferredResourceFormat()); 192 result.addErrorStatus(410);//gone 193 result.addErrorStatus(404);//unknown 194 result.addSuccessStatus(200);//Only one for now 195 if(result.isUnsuccessfulRequest()) { 196 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 197 } 198 } catch (Exception e) { 199 handleException("An error has occurred while trying to read this resource", e); 200 } 201 return result.getPayload(); 202 } 203 204 public <T extends Resource> T vread(Class<T> resourceClass, String id, String version) { 205 ResourceRequest<T> result = null; 206 try { 207 result = utils.issueGetResourceRequest(resourceAddress.resolveGetUriFromResourceClassAndIdAndVersion(resourceClass, id, version), getPreferredResourceFormat()); 208 result.addErrorStatus(410);//gone 209 result.addErrorStatus(404);//unknown 210 result.addErrorStatus(405);//unknown 211 result.addSuccessStatus(200);//Only one for now 212 if(result.isUnsuccessfulRequest()) { 213 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 214 } 215 } catch (Exception e) { 216 handleException("An error has occurred while trying to read this version of the resource", e); 217 } 218 return result.getPayload(); 219 } 220 221 // GET fhir/ValueSet?url=http://hl7.org/fhir/ValueSet/clinical-findings&version=0.8 222 223 public <T extends Resource> T getCanonical(Class<T> resourceClass, String canonicalURL) { 224 ResourceRequest<T> result = null; 225 try { 226 result = utils.issueGetResourceRequest(resourceAddress.resolveGetUriFromResourceClassAndCanonical(resourceClass, canonicalURL), getPreferredResourceFormat()); 227 result.addErrorStatus(410);//gone 228 result.addErrorStatus(404);//unknown 229 result.addErrorStatus(405);//unknown 230 result.addSuccessStatus(200);//Only one for now 231 if(result.isUnsuccessfulRequest()) { 232 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 233 } 234 } catch (Exception e) { 235 handleException("An error has occurred while trying to read this version of the resource", e); 236 } 237 Bundle bnd = (Bundle) result.getPayload(); 238 if (bnd.getEntry().size() == 0) 239 throw new EFhirClientException("No matching resource found for canonical URL '"+canonicalURL+"'"); 240 if (bnd.getEntry().size() > 1) 241 throw new EFhirClientException("Multiple matching resources found for canonical URL '"+canonicalURL+"'"); 242 return (T) bnd.getEntry().get(0).getResource(); 243 } 244 245// 246// public <T extends Resource> T update(Class<T> resourceClass, T resource, String id) { 247// ResourceRequest<T> result = null; 248// try { 249// List<Header> headers = null; 250// result = utils.issuePutRequest(resourceAddress.resolveGetUriFromResourceClassAndId(resourceClass, id),utils.getResourceAsByteArray(resource, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers, proxy); 251// result.addErrorStatus(410);//gone 252// result.addErrorStatus(404);//unknown 253// result.addErrorStatus(405); 254// result.addErrorStatus(422);//Unprocessable Entity 255// result.addSuccessStatus(200); 256// result.addSuccessStatus(201); 257// if(result.isUnsuccessfulRequest()) { 258// throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 259// } 260// } catch(Exception e) { 261// throw new EFhirClientException("An error has occurred while trying to update this resource", e); 262// } 263// // TODO oe 26.1.2015 could be made nicer if only OperationOutcome locationheader is returned with an operationOutcome would be returned (and not the resource also) we make another read 264// try { 265// OperationOutcome operationOutcome = (OperationOutcome)result.getPayload(); 266// ResourceAddress.ResourceVersionedIdentifier resVersionedIdentifier = ResourceAddress.parseCreateLocation(result.getLocation()); 267// return this.vread(resourceClass, resVersionedIdentifier.getId(),resVersionedIdentifier.getVersionId()); 268// } catch(ClassCastException e) { 269// // if we fall throught we have the correct type already in the create 270// } 271// 272// return result.getPayload(); 273// } 274 275// 276// public <T extends Resource> boolean delete(Class<T> resourceClass, String id) { 277// try { 278// return utils.issueDeleteRequest(resourceAddress.resolveGetUriFromResourceClassAndId(resourceClass, id), proxy); 279// } catch(Exception e) { 280// throw new EFhirClientException("An error has occurred while trying to delete this resource", e); 281// } 282// 283// } 284 285// 286// public <T extends Resource> OperationOutcome create(Class<T> resourceClass, T resource) { 287// ResourceRequest<T> resourceRequest = null; 288// try { 289// List<Header> headers = null; 290// resourceRequest = utils.issuePostRequest(resourceAddress.resolveGetUriFromResourceClass(resourceClass),utils.getResourceAsByteArray(resource, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers, proxy); 291// resourceRequest.addSuccessStatus(201); 292// if(resourceRequest.isUnsuccessfulRequest()) { 293// throw new EFhirClientException("Server responded with HTTP error code " + resourceRequest.getHttpStatus(), (OperationOutcome)resourceRequest.getPayload()); 294// } 295// } catch(Exception e) { 296// handleException("An error has occurred while trying to create this resource", e); 297// } 298// OperationOutcome operationOutcome = null;; 299// try { 300// operationOutcome = (OperationOutcome)resourceRequest.getPayload(); 301// ResourceAddress.ResourceVersionedIdentifier resVersionedIdentifier = 302// ResourceAddress.parseCreateLocation(resourceRequest.getLocation()); 303// OperationOutcomeIssueComponent issue = operationOutcome.addIssue(); 304// issue.setSeverity(IssueSeverity.INFORMATION); 305// issue.setUserData(ResourceAddress.ResourceVersionedIdentifier.class.toString(), 306// resVersionedIdentifier); 307// return operationOutcome; 308// } catch(ClassCastException e) { 309// // some server (e.g. grahams) returns the resource directly 310// operationOutcome = new OperationOutcome(); 311// OperationOutcomeIssueComponent issue = operationOutcome.addIssue(); 312// issue.setSeverity(IssueSeverity.INFORMATION); 313// issue.setUserData(ResourceRequest.class.toString(), 314// resourceRequest.getPayload()); 315// return operationOutcome; 316// } 317// } 318 319// 320// public <T extends Resource> Bundle history(Calendar lastUpdate, Class<T> resourceClass, String id) { 321// Bundle history = null; 322// try { 323// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceId(resourceClass, id, lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 324// } catch (Exception e) { 325// handleException("An error has occurred while trying to retrieve history information for this resource", e); 326// } 327// return history; 328// } 329 330// 331// public <T extends Resource> Bundle history(Date lastUpdate, Class<T> resourceClass, String id) { 332// Bundle history = null; 333// try { 334// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceId(resourceClass, id, lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 335// } catch (Exception e) { 336// handleException("An error has occurred while trying to retrieve history information for this resource", e); 337// } 338// return history; 339// } 340// 341// 342// public <T extends Resource> Bundle history(Calendar lastUpdate, Class<T> resourceClass) { 343// Bundle history = null; 344// try { 345// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceType(resourceClass, lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 346// } catch (Exception e) { 347// handleException("An error has occurred while trying to retrieve history information for this resource type", e); 348// } 349// return history; 350// } 351// 352// 353// public <T extends Resource> Bundle history(Date lastUpdate, Class<T> resourceClass) { 354// Bundle history = null; 355// try { 356// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceType(resourceClass, lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 357// } catch (Exception e) { 358// handleException("An error has occurred while trying to retrieve history information for this resource type", e); 359// } 360// return history; 361// } 362// 363// 364// public <T extends Resource> Bundle history(Class<T> resourceClass) { 365// Bundle history = null; 366// try { 367// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceType(resourceClass, maxResultSetSize), getPreferredResourceFormat(), proxy); 368// } catch (Exception e) { 369// handleException("An error has occurred while trying to retrieve history information for this resource type", e); 370// } 371// return history; 372// } 373// 374// 375// public <T extends Resource> Bundle history(Class<T> resourceClass, String id) { 376// Bundle history = null; 377// try { 378// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceId(resourceClass, id, maxResultSetSize), getPreferredResourceFormat(), proxy); 379// } catch (Exception e) { 380// handleException("An error has occurred while trying to retrieve history information for this resource", e); 381// } 382// return history; 383// } 384// 385// 386// public <T extends Resource> Bundle history(Date lastUpdate) { 387// Bundle history = null; 388// try { 389// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForAllResources(lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 390// } catch (Exception e) { 391// handleException("An error has occurred while trying to retrieve history since last update",e); 392// } 393// return history; 394// } 395// 396// 397// public <T extends Resource> Bundle history(Calendar lastUpdate) { 398// Bundle history = null; 399// try { 400// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForAllResources(lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 401// } catch (Exception e) { 402// handleException("An error has occurred while trying to retrieve history since last update",e); 403// } 404// return history; 405// } 406// 407// 408// public <T extends Resource> Bundle history() { 409// Bundle history = null; 410// try { 411// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForAllResources(maxResultSetSize), getPreferredResourceFormat(), proxy); 412// } catch (Exception e) { 413// handleException("An error has occurred while trying to retrieve history since last update",e); 414// } 415// return history; 416// } 417// 418// 419// public <T extends Resource> Bundle search(Class<T> resourceClass, Map<String, String> parameters) { 420// Bundle searchResults = null; 421// try { 422// searchResults = utils.issueGetFeedRequest(resourceAddress.resolveSearchUri(resourceClass, parameters), getPreferredResourceFormat(), proxy); 423// } catch (Exception e) { 424// handleException("Error performing search with parameters " + parameters, e); 425// } 426// return searchResults; 427// } 428// 429// 430// public <T extends Resource> Bundle searchPost(Class<T> resourceClass, T resource, Map<String, String> parameters) { 431// Bundle searchResults = null; 432// try { 433// searchResults = utils.issuePostFeedRequest(resourceAddress.resolveSearchUri(resourceClass, new HashMap<String, String>()), parameters, "src", resource, getPreferredResourceFormat()); 434// } catch (Exception e) { 435// handleException("Error performing search with parameters " + parameters, e); 436// } 437// return searchResults; 438// } 439 440 441 public <T extends Resource> Parameters operateType(Class<T> resourceClass, String name, Parameters params) { 442 boolean complex = false; 443 for (ParametersParameterComponent p : params.getParameter()) 444 complex = complex || !(p.getValue() instanceof PrimitiveType); 445 Parameters searchResults = null; 446 String ps = ""; 447 try { 448 if (!complex) 449 for (ParametersParameterComponent p : params.getParameter()) 450 if (p.getValue() instanceof PrimitiveType) 451 ps += p.getName() + "=" + Utilities.encodeUri(((PrimitiveType) p.getValue()).asStringValue())+"&"; 452 ResourceRequest<T> result; 453 if (complex) 454 result = utils.issuePostRequest(resourceAddress.resolveOperationURLFromClass(resourceClass, name, ps), utils.getResourceAsByteArray(params, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat()); 455 else 456 result = utils.issueGetResourceRequest(resourceAddress.resolveOperationURLFromClass(resourceClass, name, ps), getPreferredResourceFormat()); 457 result.addErrorStatus(410);//gone 458 result.addErrorStatus(404);//unknown 459 result.addSuccessStatus(200);//Only one for now 460 if(result.isUnsuccessfulRequest()) 461 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 462 if (result.getPayload() instanceof Parameters) 463 return (Parameters) result.getPayload(); 464 else { 465 Parameters p_out = new Parameters(); 466 p_out.addParameter().setName("return").setResource(result.getPayload()); 467 return p_out; 468 } 469 } catch (Exception e) { 470 handleException("Error performing operation '"+name+"' with parameters " + ps, e); 471 } 472 return null; 473 } 474 475 476 public Bundle transaction(Bundle batch) { 477 Bundle transactionResult = null; 478 try { 479 transactionResult = utils.postBatchRequest(resourceAddress.getBaseServiceUri(), utils.getFeedAsByteArray(batch, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat()); 480 } catch (Exception e) { 481 handleException("An error occurred trying to process this transaction request", e); 482 } 483 return transactionResult; 484 } 485 486 @SuppressWarnings("unchecked") 487 488 public <T extends Resource> OperationOutcome validate(Class<T> resourceClass, T resource, String id) { 489 ResourceRequest<T> result = null; 490 try { 491 result = utils.issuePostRequest(resourceAddress.resolveValidateUri(resourceClass, id), utils.getResourceAsByteArray(resource, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat()); 492 result.addErrorStatus(400);//gone 493 result.addErrorStatus(422);//Unprocessable Entity 494 result.addSuccessStatus(200);//OK 495 if(result.isUnsuccessfulRequest()) { 496 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 497 } 498 } catch(Exception e) { 499 handleException("An error has occurred while trying to validate this resource", e); 500 } 501 return (OperationOutcome)result.getPayload(); 502 } 503 504 /* change to meta operations 505 506 public List<Coding> getAllTags() { 507 TagListRequest result = null; 508 try { 509 result = utils.issueGetRequestForTagList(resourceAddress.resolveGetAllTags(), getPreferredResourceFormat(), null, proxy); 510 } catch (Exception e) { 511 handleException("An error has occurred while trying to retrieve all tags", e); 512 } 513 return result.getPayload(); 514 } 515 516 517 public <T extends Resource> List<Coding> getAllTagsForResourceType(Class<T> resourceClass) { 518 TagListRequest result = null; 519 try { 520 result = utils.issueGetRequestForTagList(resourceAddress.resolveGetAllTagsForResourceType(resourceClass), getPreferredResourceFormat(), null, proxy); 521 } catch (Exception e) { 522 handleException("An error has occurred while trying to retrieve tags for this resource type", e); 523 } 524 return result.getPayload(); 525 } 526 527 528 public <T extends Resource> List<Coding> getTagsForReference(Class<T> resource, String id) { 529 TagListRequest result = null; 530 try { 531 result = utils.issueGetRequestForTagList(resourceAddress.resolveGetTagsForReference(resource, id), getPreferredResourceFormat(), null, proxy); 532 } catch (Exception e) { 533 handleException("An error has occurred while trying to retrieve tags for this resource", e); 534 } 535 return result.getPayload(); 536 } 537 538 539 public <T extends Resource> List<Coding> getTagsForResourceVersion(Class<T> resource, String id, String versionId) { 540 TagListRequest result = null; 541 try { 542 result = utils.issueGetRequestForTagList(resourceAddress.resolveGetTagsForResourceVersion(resource, id, versionId), getPreferredResourceFormat(), null, proxy); 543 } catch (Exception e) { 544 handleException("An error has occurred while trying to retrieve tags for this resource version", e); 545 } 546 return result.getPayload(); 547 } 548 549// 550// public <T extends Resource> boolean deleteTagsForReference(Class<T> resourceClass, String id) { 551// try { 552// return utils.issueDeleteRequest(resourceAddress.resolveGetTagsForReference(resourceClass, id), proxy); 553// } catch(Exception e) { 554// handleException("An error has occurred while trying to retrieve tags for this resource version", e); 555// throw new EFhirClientException("An error has occurred while trying to delete this resource", e); 556// } 557// 558// } 559// 560// 561// public <T extends Resource> boolean deleteTagsForResourceVersion(Class<T> resourceClass, String id, List<Coding> tags, String version) { 562// try { 563// return utils.issueDeleteRequest(resourceAddress.resolveGetTagsForResourceVersion(resourceClass, id, version), proxy); 564// } catch(Exception e) { 565// handleException("An error has occurred while trying to retrieve tags for this resource version", e); 566// throw new EFhirClientException("An error has occurred while trying to delete this resource", e); 567// } 568// } 569 570 571 public <T extends Resource> List<Coding> createTags(List<Coding> tags, Class<T> resourceClass, String id) { 572 TagListRequest request = null; 573 try { 574 request = utils.issuePostRequestForTagList(resourceAddress.resolveGetTagsForReference(resourceClass, id),utils.getTagListAsByteArray(tags, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), null, proxy); 575 request.addSuccessStatus(201); 576 request.addSuccessStatus(200); 577 if(request.isUnsuccessfulRequest()) { 578 throw new EFhirClientException("Server responded with HTTP error code " + request.getHttpStatus()); 579 } 580 } catch(Exception e) { 581 handleException("An error has occurred while trying to set tags for this resource", e); 582 } 583 return request.getPayload(); 584 } 585 586 587 public <T extends Resource> List<Coding> createTags(List<Coding> tags, Class<T> resourceClass, String id, String version) { 588 TagListRequest request = null; 589 try { 590 request = utils.issuePostRequestForTagList(resourceAddress.resolveGetTagsForResourceVersion(resourceClass, id, version),utils.getTagListAsByteArray(tags, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), null, proxy); 591 request.addSuccessStatus(201); 592 request.addSuccessStatus(200); 593 if(request.isUnsuccessfulRequest()) { 594 throw new EFhirClientException("Server responded with HTTP error code " + request.getHttpStatus()); 595 } 596 } catch(Exception e) { 597 handleException("An error has occurred while trying to set the tags for this resource version", e); 598 } 599 return request.getPayload(); 600 } 601 602 603 public <T extends Resource> List<Coding> deleteTags(List<Coding> tags, Class<T> resourceClass, String id, String version) { 604 TagListRequest request = null; 605 try { 606 request = utils.issuePostRequestForTagList(resourceAddress.resolveDeleteTagsForResourceVersion(resourceClass, id, version),utils.getTagListAsByteArray(tags, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), null, proxy); 607 request.addSuccessStatus(201); 608 request.addSuccessStatus(200); 609 if(request.isUnsuccessfulRequest()) { 610 throw new EFhirClientException("Server responded with HTTP error code " + request.getHttpStatus()); 611 } 612 } catch(Exception e) { 613 handleException("An error has occurred while trying to delete the tags for this resource version", e); 614 } 615 return request.getPayload(); 616 } 617 */ 618 619 /** 620 * Helper method to prevent nesting of previously thrown EFhirClientExceptions 621 * 622 * @param e 623 * @throws EFhirClientException 624 */ 625 protected void handleException(String message, Exception e) throws EFhirClientException { 626 if(e instanceof EFhirClientException) { 627 throw (EFhirClientException)e; 628 } else { 629 throw new EFhirClientException(message, e); 630 } 631 } 632 633 /** 634 * Helper method to determine whether desired resource representation 635 * is Json or XML. 636 * 637 * @param format 638 * @return 639 */ 640 protected boolean isJson(String format) { 641 boolean isJson = false; 642 if(format.toLowerCase().contains("json")) { 643 isJson = true; 644 } 645 return isJson; 646 } 647 648 public Bundle fetchFeed(String url) { 649 Bundle feed = null; 650 try { 651 feed = utils.issueGetFeedRequest(new URI(url), getPreferredResourceFormat()); 652 } catch (Exception e) { 653 handleException("An error has occurred while trying to retrieve history since last update",e); 654 } 655 return feed; 656 } 657 658 public ValueSet expandValueset(ValueSet source, Parameters expParams) { 659 List<Header> headers = null; 660 Parameters p = expParams == null ? new Parameters() : expParams.copy(); 661 p.addParameter().setName("valueSet").setResource(source); 662 ResourceRequest<Resource> result = utils.issuePostRequest(resourceAddress.resolveOperationUri(ValueSet.class, "expand"), 663 utils.getResourceAsByteArray(p, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers); 664 result.addErrorStatus(410);//gone 665 result.addErrorStatus(404);//unknown 666 result.addErrorStatus(405); 667 result.addErrorStatus(422);//Unprocessable Entity 668 result.addSuccessStatus(200); 669 result.addSuccessStatus(201); 670 if(result.isUnsuccessfulRequest()) { 671 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 672 } 673 return (ValueSet) result.getPayload(); 674 } 675 676 677 public Parameters lookupCode(Map<String, String> params) { 678 ResourceRequest<Resource> result = utils.issueGetResourceRequest(resourceAddress.resolveOperationUri(CodeSystem.class, "lookup", params), getPreferredResourceFormat()); 679 result.addErrorStatus(410);//gone 680 result.addErrorStatus(404);//unknown 681 result.addErrorStatus(405); 682 result.addErrorStatus(422);//Unprocessable Entity 683 result.addSuccessStatus(200); 684 result.addSuccessStatus(201); 685 if(result.isUnsuccessfulRequest()) { 686 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 687 } 688 return (Parameters) result.getPayload(); 689 } 690 public ValueSet expandValueset(ValueSet source, Parameters expParams, Map<String, String> params) { 691 List<Header> headers = null; 692 Parameters p = expParams == null ? new Parameters() : expParams.copy(); 693 p.addParameter().setName("valueSet").setResource(source); 694 for (String n : params.keySet()) 695 p.addParameter().setName(n).setValue(new StringType(params.get(n))); 696 ResourceRequest<Resource> result = utils.issuePostRequest(resourceAddress.resolveOperationUri(ValueSet.class, "expand", params), 697 utils.getResourceAsByteArray(p, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers); 698 result.addErrorStatus(410);//gone 699 result.addErrorStatus(404);//unknown 700 result.addErrorStatus(405); 701 result.addErrorStatus(422);//Unprocessable Entity 702 result.addSuccessStatus(200); 703 result.addSuccessStatus(201); 704 if(result.isUnsuccessfulRequest()) { 705 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 706 } 707 return (ValueSet) result.getPayload(); 708 } 709 710// public ValueSet expandValueset(ValueSet source, ExpansionProfile profile, Map<String, String> params) { 711// List<Header> headers = null; 712// ResourceRequest<Resource> result = utils.issuePostRequest(resourceAddress.resolveOperationUri(ValueSet.class, "expand", params), 713// utils.getResourceAsByteArray(source, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers, proxy); 714// result.addErrorStatus(410);//gone 715// result.addErrorStatus(404);//unknown 716// result.addErrorStatus(405); 717// result.addErrorStatus(422);//Unprocessable Entity 718// result.addSuccessStatus(200); 719// result.addSuccessStatus(201); 720// if(result.isUnsuccessfulRequest()) { 721// throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 722// } 723// return (ValueSet) result.getPayload(); 724// } 725 726 727 public String getAddress() { 728 return base; 729 } 730 731 public ConceptMap initializeClosure(String name) { 732 Parameters params = new Parameters(); 733 params.addParameter().setName("name").setValue(new StringType(name)); 734 List<Header> headers = null; 735 ResourceRequest<Resource> result = utils.issuePostRequest(resourceAddress.resolveOperationUri(null, "closure", new HashMap<String, String>()), 736 utils.getResourceAsByteArray(params, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers); 737 result.addErrorStatus(410);//gone 738 result.addErrorStatus(404);//unknown 739 result.addErrorStatus(405); 740 result.addErrorStatus(422);//Unprocessable Entity 741 result.addSuccessStatus(200); 742 result.addSuccessStatus(201); 743 if(result.isUnsuccessfulRequest()) { 744 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 745 } 746 return (ConceptMap) result.getPayload(); 747 } 748 749 public ConceptMap updateClosure(String name, Coding coding) { 750 Parameters params = new Parameters(); 751 params.addParameter().setName("name").setValue(new StringType(name)); 752 params.addParameter().setName("concept").setValue(coding); 753 List<Header> headers = null; 754 ResourceRequest<Resource> result = utils.issuePostRequest(resourceAddress.resolveOperationUri(null, "closure", new HashMap<String, String>()), 755 utils.getResourceAsByteArray(params, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers); 756 result.addErrorStatus(410);//gone 757 result.addErrorStatus(404);//unknown 758 result.addErrorStatus(405); 759 result.addErrorStatus(422);//Unprocessable Entity 760 result.addSuccessStatus(200); 761 result.addSuccessStatus(201); 762 if(result.isUnsuccessfulRequest()) { 763 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 764 } 765 return (ConceptMap) result.getPayload(); 766 } 767 768 public int getTimeout() { 769 return utils.getTimeout(); 770 } 771 772 public void setTimeout(int timeout) { 773 utils.setTimeout(timeout); 774 } 775 776 public String getUsername() { 777 return utils.getUsername(); 778 } 779 780 public void setUsername(String username) { 781 utils.setUsername(username); 782 } 783 784 public String getPassword() { 785 return utils.getPassword(); 786 } 787 788 public void setPassword(String password) { 789 utils.setPassword(password); 790 } 791 792 public ToolingClientLogger getLogger() { 793 return utils.getLogger(); 794 } 795 796 public void setLogger(ToolingClientLogger logger) { 797 utils.setLogger(logger); 798 } 799 800 801}