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.ExpansionProfile; 047import org.hl7.fhir.r4.model.OperationOutcome; 048import org.hl7.fhir.r4.model.Parameters; 049import org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent; 050import org.hl7.fhir.r4.model.PrimitiveType; 051import org.hl7.fhir.r4.model.Resource; 052import org.hl7.fhir.r4.model.StringType; 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 CapabilityStatement getCapabilitiesStatement() { 164 CapabilityStatement conformance = null; 165 try { 166 conformance = (CapabilityStatement)utils.issueGetResourceRequest(resourceAddress.resolveMetadataUri(false), getPreferredResourceFormat()).getReference(); 167 } catch(Exception e) { 168 handleException("An error has occurred while trying to fetch the server's conformance statement", e); 169 } 170 return conformance; 171 } 172 173 public CapabilityStatement getCapabilitiesStatementQuick() throws EFhirClientException { 174 if (capabilities != null) 175 return capabilities; 176 try { 177 capabilities = (CapabilityStatement)utils.issueGetResourceRequest(resourceAddress.resolveMetadataUri(true), getPreferredResourceFormat()).getReference(); 178 } catch(Exception e) { 179 handleException("An error has occurred while trying to fetch the server's conformance statement", e); 180 } 181 return capabilities; 182 } 183 184 public <T extends Resource> T read(Class<T> resourceClass, String id) {//TODO Change this to AddressableResource 185 ResourceRequest<T> result = null; 186 try { 187 result = utils.issueGetResourceRequest(resourceAddress.resolveGetUriFromResourceClassAndId(resourceClass, id), getPreferredResourceFormat()); 188 result.addErrorStatus(410);//gone 189 result.addErrorStatus(404);//unknown 190 result.addSuccessStatus(200);//Only one for now 191 if(result.isUnsuccessfulRequest()) { 192 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 193 } 194 } catch (Exception e) { 195 handleException("An error has occurred while trying to read this resource", e); 196 } 197 return result.getPayload(); 198 } 199 200 public <T extends Resource> T vread(Class<T> resourceClass, String id, String version) { 201 ResourceRequest<T> result = null; 202 try { 203 result = utils.issueGetResourceRequest(resourceAddress.resolveGetUriFromResourceClassAndIdAndVersion(resourceClass, id, version), getPreferredResourceFormat()); 204 result.addErrorStatus(410);//gone 205 result.addErrorStatus(404);//unknown 206 result.addErrorStatus(405);//unknown 207 result.addSuccessStatus(200);//Only one for now 208 if(result.isUnsuccessfulRequest()) { 209 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 210 } 211 } catch (Exception e) { 212 handleException("An error has occurred while trying to read this version of the resource", e); 213 } 214 return result.getPayload(); 215 } 216 217 // GET fhir/ValueSet?url=http://hl7.org/fhir/ValueSet/clinical-findings&version=0.8 218 219 public <T extends Resource> T getCanonical(Class<T> resourceClass, String canonicalURL) { 220 ResourceRequest<T> result = null; 221 try { 222 result = utils.issueGetResourceRequest(resourceAddress.resolveGetUriFromResourceClassAndCanonical(resourceClass, canonicalURL), getPreferredResourceFormat()); 223 result.addErrorStatus(410);//gone 224 result.addErrorStatus(404);//unknown 225 result.addErrorStatus(405);//unknown 226 result.addSuccessStatus(200);//Only one for now 227 if(result.isUnsuccessfulRequest()) { 228 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 229 } 230 } catch (Exception e) { 231 handleException("An error has occurred while trying to read this version of the resource", e); 232 } 233 Bundle bnd = (Bundle) result.getPayload(); 234 if (bnd.getEntry().size() == 0) 235 throw new EFhirClientException("No matching resource found for canonical URL '"+canonicalURL+"'"); 236 if (bnd.getEntry().size() > 1) 237 throw new EFhirClientException("Multiple matching resources found for canonical URL '"+canonicalURL+"'"); 238 return (T) bnd.getEntry().get(0).getResource(); 239 } 240 241// 242// public <T extends Resource> T update(Class<T> resourceClass, T resource, String id) { 243// ResourceRequest<T> result = null; 244// try { 245// List<Header> headers = null; 246// result = utils.issuePutRequest(resourceAddress.resolveGetUriFromResourceClassAndId(resourceClass, id),utils.getResourceAsByteArray(resource, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers, proxy); 247// result.addErrorStatus(410);//gone 248// result.addErrorStatus(404);//unknown 249// result.addErrorStatus(405); 250// result.addErrorStatus(422);//Unprocessable Entity 251// result.addSuccessStatus(200); 252// result.addSuccessStatus(201); 253// if(result.isUnsuccessfulRequest()) { 254// throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 255// } 256// } catch(Exception e) { 257// throw new EFhirClientException("An error has occurred while trying to update this resource", e); 258// } 259// // 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 260// try { 261// OperationOutcome operationOutcome = (OperationOutcome)result.getPayload(); 262// ResourceAddress.ResourceVersionedIdentifier resVersionedIdentifier = ResourceAddress.parseCreateLocation(result.getLocation()); 263// return this.vread(resourceClass, resVersionedIdentifier.getId(),resVersionedIdentifier.getVersionId()); 264// } catch(ClassCastException e) { 265// // if we fall throught we have the correct type already in the create 266// } 267// 268// return result.getPayload(); 269// } 270 271// 272// public <T extends Resource> boolean delete(Class<T> resourceClass, String id) { 273// try { 274// return utils.issueDeleteRequest(resourceAddress.resolveGetUriFromResourceClassAndId(resourceClass, id), proxy); 275// } catch(Exception e) { 276// throw new EFhirClientException("An error has occurred while trying to delete this resource", e); 277// } 278// 279// } 280 281// 282// public <T extends Resource> OperationOutcome create(Class<T> resourceClass, T resource) { 283// ResourceRequest<T> resourceRequest = null; 284// try { 285// List<Header> headers = null; 286// resourceRequest = utils.issuePostRequest(resourceAddress.resolveGetUriFromResourceClass(resourceClass),utils.getResourceAsByteArray(resource, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers, proxy); 287// resourceRequest.addSuccessStatus(201); 288// if(resourceRequest.isUnsuccessfulRequest()) { 289// throw new EFhirClientException("Server responded with HTTP error code " + resourceRequest.getHttpStatus(), (OperationOutcome)resourceRequest.getPayload()); 290// } 291// } catch(Exception e) { 292// handleException("An error has occurred while trying to create this resource", e); 293// } 294// OperationOutcome operationOutcome = null;; 295// try { 296// operationOutcome = (OperationOutcome)resourceRequest.getPayload(); 297// ResourceAddress.ResourceVersionedIdentifier resVersionedIdentifier = 298// ResourceAddress.parseCreateLocation(resourceRequest.getLocation()); 299// OperationOutcomeIssueComponent issue = operationOutcome.addIssue(); 300// issue.setSeverity(IssueSeverity.INFORMATION); 301// issue.setUserData(ResourceAddress.ResourceVersionedIdentifier.class.toString(), 302// resVersionedIdentifier); 303// return operationOutcome; 304// } catch(ClassCastException e) { 305// // some server (e.g. grahams) returns the resource directly 306// operationOutcome = new OperationOutcome(); 307// OperationOutcomeIssueComponent issue = operationOutcome.addIssue(); 308// issue.setSeverity(IssueSeverity.INFORMATION); 309// issue.setUserData(ResourceRequest.class.toString(), 310// resourceRequest.getPayload()); 311// return operationOutcome; 312// } 313// } 314 315// 316// public <T extends Resource> Bundle history(Calendar lastUpdate, Class<T> resourceClass, String id) { 317// Bundle history = null; 318// try { 319// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceId(resourceClass, id, lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 320// } catch (Exception e) { 321// handleException("An error has occurred while trying to retrieve history information for this resource", e); 322// } 323// return history; 324// } 325 326// 327// public <T extends Resource> Bundle history(Date lastUpdate, Class<T> resourceClass, String id) { 328// Bundle history = null; 329// try { 330// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceId(resourceClass, id, lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 331// } catch (Exception e) { 332// handleException("An error has occurred while trying to retrieve history information for this resource", e); 333// } 334// return history; 335// } 336// 337// 338// public <T extends Resource> Bundle history(Calendar lastUpdate, Class<T> resourceClass) { 339// Bundle history = null; 340// try { 341// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceType(resourceClass, lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 342// } catch (Exception e) { 343// handleException("An error has occurred while trying to retrieve history information for this resource type", e); 344// } 345// return history; 346// } 347// 348// 349// public <T extends Resource> Bundle history(Date lastUpdate, Class<T> resourceClass) { 350// Bundle history = null; 351// try { 352// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceType(resourceClass, lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 353// } catch (Exception e) { 354// handleException("An error has occurred while trying to retrieve history information for this resource type", e); 355// } 356// return history; 357// } 358// 359// 360// public <T extends Resource> Bundle history(Class<T> resourceClass) { 361// Bundle history = null; 362// try { 363// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceType(resourceClass, maxResultSetSize), getPreferredResourceFormat(), proxy); 364// } catch (Exception e) { 365// handleException("An error has occurred while trying to retrieve history information for this resource type", e); 366// } 367// return history; 368// } 369// 370// 371// public <T extends Resource> Bundle history(Class<T> resourceClass, String id) { 372// Bundle history = null; 373// try { 374// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceId(resourceClass, id, maxResultSetSize), getPreferredResourceFormat(), proxy); 375// } catch (Exception e) { 376// handleException("An error has occurred while trying to retrieve history information for this resource", e); 377// } 378// return history; 379// } 380// 381// 382// public <T extends Resource> Bundle history(Date lastUpdate) { 383// Bundle history = null; 384// try { 385// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForAllResources(lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 386// } catch (Exception e) { 387// handleException("An error has occurred while trying to retrieve history since last update",e); 388// } 389// return history; 390// } 391// 392// 393// public <T extends Resource> Bundle history(Calendar lastUpdate) { 394// Bundle history = null; 395// try { 396// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForAllResources(lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 397// } catch (Exception e) { 398// handleException("An error has occurred while trying to retrieve history since last update",e); 399// } 400// return history; 401// } 402// 403// 404// public <T extends Resource> Bundle history() { 405// Bundle history = null; 406// try { 407// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForAllResources(maxResultSetSize), getPreferredResourceFormat(), proxy); 408// } catch (Exception e) { 409// handleException("An error has occurred while trying to retrieve history since last update",e); 410// } 411// return history; 412// } 413// 414// 415// public <T extends Resource> Bundle search(Class<T> resourceClass, Map<String, String> parameters) { 416// Bundle searchResults = null; 417// try { 418// searchResults = utils.issueGetFeedRequest(resourceAddress.resolveSearchUri(resourceClass, parameters), getPreferredResourceFormat(), proxy); 419// } catch (Exception e) { 420// handleException("Error performing search with parameters " + parameters, e); 421// } 422// return searchResults; 423// } 424// 425// 426// public <T extends Resource> Bundle searchPost(Class<T> resourceClass, T resource, Map<String, String> parameters) { 427// Bundle searchResults = null; 428// try { 429// searchResults = utils.issuePostFeedRequest(resourceAddress.resolveSearchUri(resourceClass, new HashMap<String, String>()), parameters, "src", resource, getPreferredResourceFormat()); 430// } catch (Exception e) { 431// handleException("Error performing search with parameters " + parameters, e); 432// } 433// return searchResults; 434// } 435 436 437 public <T extends Resource> Parameters operateType(Class<T> resourceClass, String name, Parameters params) { 438 boolean complex = false; 439 for (ParametersParameterComponent p : params.getParameter()) 440 complex = complex || !(p.getValue() instanceof PrimitiveType); 441 Parameters searchResults = null; 442 String ps = ""; 443 try { 444 if (!complex) 445 for (ParametersParameterComponent p : params.getParameter()) 446 if (p.getValue() instanceof PrimitiveType) 447 ps += p.getName() + "=" + Utilities.encodeUri(((PrimitiveType) p.getValue()).asStringValue())+"&"; 448 ResourceRequest<T> result; 449 if (complex) 450 result = utils.issuePostRequest(resourceAddress.resolveOperationURLFromClass(resourceClass, name, ps), utils.getResourceAsByteArray(params, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat()); 451 else 452 result = utils.issueGetResourceRequest(resourceAddress.resolveOperationURLFromClass(resourceClass, name, ps), getPreferredResourceFormat()); 453 result.addErrorStatus(410);//gone 454 result.addErrorStatus(404);//unknown 455 result.addSuccessStatus(200);//Only one for now 456 if(result.isUnsuccessfulRequest()) 457 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 458 if (result.getPayload() instanceof Parameters) 459 return (Parameters) result.getPayload(); 460 else { 461 Parameters p_out = new Parameters(); 462 p_out.addParameter().setName("return").setResource(result.getPayload()); 463 return p_out; 464 } 465 } catch (Exception e) { 466 handleException("Error performing operation '"+name+"' with parameters " + ps, e); 467 } 468 return null; 469 } 470 471 472 public Bundle transaction(Bundle batch) { 473 Bundle transactionResult = null; 474 try { 475 transactionResult = utils.postBatchRequest(resourceAddress.getBaseServiceUri(), utils.getFeedAsByteArray(batch, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat()); 476 } catch (Exception e) { 477 handleException("An error occurred trying to process this transaction request", e); 478 } 479 return transactionResult; 480 } 481 482 @SuppressWarnings("unchecked") 483 484 public <T extends Resource> OperationOutcome validate(Class<T> resourceClass, T resource, String id) { 485 ResourceRequest<T> result = null; 486 try { 487 result = utils.issuePostRequest(resourceAddress.resolveValidateUri(resourceClass, id), utils.getResourceAsByteArray(resource, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat()); 488 result.addErrorStatus(400);//gone 489 result.addErrorStatus(422);//Unprocessable Entity 490 result.addSuccessStatus(200);//OK 491 if(result.isUnsuccessfulRequest()) { 492 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 493 } 494 } catch(Exception e) { 495 handleException("An error has occurred while trying to validate this resource", e); 496 } 497 return (OperationOutcome)result.getPayload(); 498 } 499 500 /* change to meta operations 501 502 public List<Coding> getAllTags() { 503 TagListRequest result = null; 504 try { 505 result = utils.issueGetRequestForTagList(resourceAddress.resolveGetAllTags(), getPreferredResourceFormat(), null, proxy); 506 } catch (Exception e) { 507 handleException("An error has occurred while trying to retrieve all tags", e); 508 } 509 return result.getPayload(); 510 } 511 512 513 public <T extends Resource> List<Coding> getAllTagsForResourceType(Class<T> resourceClass) { 514 TagListRequest result = null; 515 try { 516 result = utils.issueGetRequestForTagList(resourceAddress.resolveGetAllTagsForResourceType(resourceClass), getPreferredResourceFormat(), null, proxy); 517 } catch (Exception e) { 518 handleException("An error has occurred while trying to retrieve tags for this resource type", e); 519 } 520 return result.getPayload(); 521 } 522 523 524 public <T extends Resource> List<Coding> getTagsForReference(Class<T> resource, String id) { 525 TagListRequest result = null; 526 try { 527 result = utils.issueGetRequestForTagList(resourceAddress.resolveGetTagsForReference(resource, id), getPreferredResourceFormat(), null, proxy); 528 } catch (Exception e) { 529 handleException("An error has occurred while trying to retrieve tags for this resource", e); 530 } 531 return result.getPayload(); 532 } 533 534 535 public <T extends Resource> List<Coding> getTagsForResourceVersion(Class<T> resource, String id, String versionId) { 536 TagListRequest result = null; 537 try { 538 result = utils.issueGetRequestForTagList(resourceAddress.resolveGetTagsForResourceVersion(resource, id, versionId), getPreferredResourceFormat(), null, proxy); 539 } catch (Exception e) { 540 handleException("An error has occurred while trying to retrieve tags for this resource version", e); 541 } 542 return result.getPayload(); 543 } 544 545// 546// public <T extends Resource> boolean deleteTagsForReference(Class<T> resourceClass, String id) { 547// try { 548// return utils.issueDeleteRequest(resourceAddress.resolveGetTagsForReference(resourceClass, id), proxy); 549// } catch(Exception e) { 550// handleException("An error has occurred while trying to retrieve tags for this resource version", e); 551// throw new EFhirClientException("An error has occurred while trying to delete this resource", e); 552// } 553// 554// } 555// 556// 557// public <T extends Resource> boolean deleteTagsForResourceVersion(Class<T> resourceClass, String id, List<Coding> tags, String version) { 558// try { 559// return utils.issueDeleteRequest(resourceAddress.resolveGetTagsForResourceVersion(resourceClass, id, version), proxy); 560// } catch(Exception e) { 561// handleException("An error has occurred while trying to retrieve tags for this resource version", e); 562// throw new EFhirClientException("An error has occurred while trying to delete this resource", e); 563// } 564// } 565 566 567 public <T extends Resource> List<Coding> createTags(List<Coding> tags, Class<T> resourceClass, String id) { 568 TagListRequest request = null; 569 try { 570 request = utils.issuePostRequestForTagList(resourceAddress.resolveGetTagsForReference(resourceClass, id),utils.getTagListAsByteArray(tags, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), null, proxy); 571 request.addSuccessStatus(201); 572 request.addSuccessStatus(200); 573 if(request.isUnsuccessfulRequest()) { 574 throw new EFhirClientException("Server responded with HTTP error code " + request.getHttpStatus()); 575 } 576 } catch(Exception e) { 577 handleException("An error has occurred while trying to set tags for this resource", e); 578 } 579 return request.getPayload(); 580 } 581 582 583 public <T extends Resource> List<Coding> createTags(List<Coding> tags, Class<T> resourceClass, String id, String version) { 584 TagListRequest request = null; 585 try { 586 request = utils.issuePostRequestForTagList(resourceAddress.resolveGetTagsForResourceVersion(resourceClass, id, version),utils.getTagListAsByteArray(tags, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), null, proxy); 587 request.addSuccessStatus(201); 588 request.addSuccessStatus(200); 589 if(request.isUnsuccessfulRequest()) { 590 throw new EFhirClientException("Server responded with HTTP error code " + request.getHttpStatus()); 591 } 592 } catch(Exception e) { 593 handleException("An error has occurred while trying to set the tags for this resource version", e); 594 } 595 return request.getPayload(); 596 } 597 598 599 public <T extends Resource> List<Coding> deleteTags(List<Coding> tags, Class<T> resourceClass, String id, String version) { 600 TagListRequest request = null; 601 try { 602 request = utils.issuePostRequestForTagList(resourceAddress.resolveDeleteTagsForResourceVersion(resourceClass, id, version),utils.getTagListAsByteArray(tags, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), null, proxy); 603 request.addSuccessStatus(201); 604 request.addSuccessStatus(200); 605 if(request.isUnsuccessfulRequest()) { 606 throw new EFhirClientException("Server responded with HTTP error code " + request.getHttpStatus()); 607 } 608 } catch(Exception e) { 609 handleException("An error has occurred while trying to delete the tags for this resource version", e); 610 } 611 return request.getPayload(); 612 } 613 */ 614 615 /** 616 * Helper method to prevent nesting of previously thrown EFhirClientExceptions 617 * 618 * @param e 619 * @throws EFhirClientException 620 */ 621 protected void handleException(String message, Exception e) throws EFhirClientException { 622 if(e instanceof EFhirClientException) { 623 throw (EFhirClientException)e; 624 } else { 625 throw new EFhirClientException(message, e); 626 } 627 } 628 629 /** 630 * Helper method to determine whether desired resource representation 631 * is Json or XML. 632 * 633 * @param format 634 * @return 635 */ 636 protected boolean isJson(String format) { 637 boolean isJson = false; 638 if(format.toLowerCase().contains("json")) { 639 isJson = true; 640 } 641 return isJson; 642 } 643 644 public Bundle fetchFeed(String url) { 645 Bundle feed = null; 646 try { 647 feed = utils.issueGetFeedRequest(new URI(url), getPreferredResourceFormat()); 648 } catch (Exception e) { 649 handleException("An error has occurred while trying to retrieve history since last update",e); 650 } 651 return feed; 652 } 653 654 public ValueSet expandValueset(ValueSet source, ExpansionProfile profile) { 655 List<Header> headers = null; 656 Parameters p = new Parameters(); 657 p.addParameter().setName("valueSet").setResource(source); 658 if (profile != null) 659 p.addParameter().setName("profile").setResource(profile); 660 ResourceRequest<Resource> result = utils.issuePostRequest(resourceAddress.resolveOperationUri(ValueSet.class, "expand"), 661 utils.getResourceAsByteArray(p, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers); 662 result.addErrorStatus(410);//gone 663 result.addErrorStatus(404);//unknown 664 result.addErrorStatus(405); 665 result.addErrorStatus(422);//Unprocessable Entity 666 result.addSuccessStatus(200); 667 result.addSuccessStatus(201); 668 if(result.isUnsuccessfulRequest()) { 669 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 670 } 671 return (ValueSet) result.getPayload(); 672 } 673 674 675 public Parameters lookupCode(Map<String, String> params) { 676 ResourceRequest<Resource> result = utils.issueGetResourceRequest(resourceAddress.resolveOperationUri(CodeSystem.class, "lookup", params), getPreferredResourceFormat()); 677 result.addErrorStatus(410);//gone 678 result.addErrorStatus(404);//unknown 679 result.addErrorStatus(405); 680 result.addErrorStatus(422);//Unprocessable Entity 681 result.addSuccessStatus(200); 682 result.addSuccessStatus(201); 683 if(result.isUnsuccessfulRequest()) { 684 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 685 } 686 return (Parameters) result.getPayload(); 687 } 688 public ValueSet expandValueset(ValueSet source, ExpansionProfile profile, Map<String, String> params) { 689 List<Header> headers = null; 690 Parameters p = new Parameters(); 691 p.addParameter().setName("valueSet").setResource(source); 692 if (profile != null) 693 p.addParameter().setName("profile").setResource(profile); 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}