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