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