001package org.hl7.fhir.r4.utils.client; 002 003/*- 004 * #%L 005 * org.hl7.fhir.r4 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.r4.model.Bundle; 063import org.hl7.fhir.r4.model.CapabilityStatement; 064import org.hl7.fhir.r4.model.CodeSystem; 065import org.hl7.fhir.r4.model.Coding; 066import org.hl7.fhir.r4.model.ConceptMap; 067import org.hl7.fhir.r4.model.OperationOutcome; 068import org.hl7.fhir.r4.model.Parameters; 069import org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent; 070import org.hl7.fhir.r4.model.PrimitiveType; 071import org.hl7.fhir.r4.model.Resource; 072import org.hl7.fhir.r4.model.StringType; 073import org.hl7.fhir.r4.model.TerminologyCapabilities; 074import org.hl7.fhir.r4.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 TerminologyCapabilities getTerminologyCapabilities() { 185 return (TerminologyCapabilities) utils.issueGetResourceRequest(resourceAddress.resolveMetadataTxCaps(), getPreferredResourceFormat()).getReference(); 186 } 187 188 public CapabilityStatement getCapabilitiesStatement() { 189 CapabilityStatement conformance = null; 190 try { 191 conformance = (CapabilityStatement)utils.issueGetResourceRequest(resourceAddress.resolveMetadataUri(false), getPreferredResourceFormat()).getReference(); 192 } catch(Exception e) { 193 handleException("An error has occurred while trying to fetch the server's conformance statement", e); 194 } 195 return conformance; 196 } 197 198 public CapabilityStatement getCapabilitiesStatementQuick() throws EFhirClientException { 199 if (capabilities != null) 200 return capabilities; 201 try { 202 capabilities = (CapabilityStatement)utils.issueGetResourceRequest(resourceAddress.resolveMetadataUri(true), getPreferredResourceFormat()).getReference(); 203 } catch(Exception e) { 204 handleException("An error has occurred while trying to fetch the server's conformance statement", e); 205 } 206 return capabilities; 207 } 208 209 public <T extends Resource> T read(Class<T> resourceClass, String id) {//TODO Change this to AddressableResource 210 ResourceRequest<T> result = null; 211 try { 212 result = utils.issueGetResourceRequest(resourceAddress.resolveGetUriFromResourceClassAndId(resourceClass, id), getPreferredResourceFormat()); 213 result.addErrorStatus(410);//gone 214 result.addErrorStatus(404);//unknown 215 result.addSuccessStatus(200);//Only one for now 216 if(result.isUnsuccessfulRequest()) { 217 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 218 } 219 } catch (Exception e) { 220 handleException("An error has occurred while trying to read this resource", e); 221 } 222 return result.getPayload(); 223 } 224 225 public <T extends Resource> T vread(Class<T> resourceClass, String id, String version) { 226 ResourceRequest<T> result = null; 227 try { 228 result = utils.issueGetResourceRequest(resourceAddress.resolveGetUriFromResourceClassAndIdAndVersion(resourceClass, id, version), getPreferredResourceFormat()); 229 result.addErrorStatus(410);//gone 230 result.addErrorStatus(404);//unknown 231 result.addErrorStatus(405);//unknown 232 result.addSuccessStatus(200);//Only one for now 233 if(result.isUnsuccessfulRequest()) { 234 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 235 } 236 } catch (Exception e) { 237 handleException("An error has occurred while trying to read this version of the resource", e); 238 } 239 return result.getPayload(); 240 } 241 242 // GET fhir/ValueSet?url=http://hl7.org/fhir/ValueSet/clinical-findings&version=0.8 243 244 public <T extends Resource> T getCanonical(Class<T> resourceClass, String canonicalURL) { 245 ResourceRequest<T> result = null; 246 try { 247 result = utils.issueGetResourceRequest(resourceAddress.resolveGetUriFromResourceClassAndCanonical(resourceClass, canonicalURL), getPreferredResourceFormat()); 248 result.addErrorStatus(410);//gone 249 result.addErrorStatus(404);//unknown 250 result.addErrorStatus(405);//unknown 251 result.addSuccessStatus(200);//Only one for now 252 if(result.isUnsuccessfulRequest()) { 253 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 254 } 255 } catch (Exception e) { 256 handleException("An error has occurred while trying to read this version of the resource", e); 257 } 258 Bundle bnd = (Bundle) result.getPayload(); 259 if (bnd.getEntry().size() == 0) 260 throw new EFhirClientException("No matching resource found for canonical URL '"+canonicalURL+"'"); 261 if (bnd.getEntry().size() > 1) 262 throw new EFhirClientException("Multiple matching resources found for canonical URL '"+canonicalURL+"'"); 263 return (T) bnd.getEntry().get(0).getResource(); 264 } 265 266 267 public Resource update(Resource resource) { 268 ResourceRequest<Resource> result = null; 269 try { 270 List<Header> headers = null; 271 result = utils.issuePutRequest(resourceAddress.resolveGetUriFromResourceClassAndId(resource.getClass(), resource.getId()),utils.getResourceAsByteArray(resource, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers); 272 result.addErrorStatus(410);//gone 273 result.addErrorStatus(404);//unknown 274 result.addErrorStatus(405); 275 result.addErrorStatus(422);//Unprocessable Entity 276 result.addSuccessStatus(200); 277 result.addSuccessStatus(201); 278 if(result.isUnsuccessfulRequest()) { 279 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 280 } 281 } catch(Exception e) { 282 throw new EFhirClientException("An error has occurred while trying to update this resource", e); 283 } 284 // 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 285 try { 286 OperationOutcome operationOutcome = (OperationOutcome)result.getPayload(); 287 ResourceAddress.ResourceVersionedIdentifier resVersionedIdentifier = ResourceAddress.parseCreateLocation(result.getLocation()); 288 return this.vread(resource.getClass(), resVersionedIdentifier.getId(),resVersionedIdentifier.getVersionId()); 289 } catch(ClassCastException e) { 290 // if we fall throught we have the correct type already in the create 291 } 292 293 return result.getPayload(); 294 } 295 296 public <T extends Resource> T update(Class<T> resourceClass, T resource, String id) { 297 ResourceRequest<T> result = null; 298 try { 299 List<Header> headers = null; 300 result = utils.issuePutRequest(resourceAddress.resolveGetUriFromResourceClassAndId(resourceClass, id),utils.getResourceAsByteArray(resource, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers); 301 result.addErrorStatus(410);//gone 302 result.addErrorStatus(404);//unknown 303 result.addErrorStatus(405); 304 result.addErrorStatus(422);//Unprocessable Entity 305 result.addSuccessStatus(200); 306 result.addSuccessStatus(201); 307 if(result.isUnsuccessfulRequest()) { 308 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 309 } 310 } catch(Exception e) { 311 throw new EFhirClientException("An error has occurred while trying to update this resource", e); 312 } 313 // 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 314 try { 315 OperationOutcome operationOutcome = (OperationOutcome)result.getPayload(); 316 ResourceAddress.ResourceVersionedIdentifier resVersionedIdentifier = ResourceAddress.parseCreateLocation(result.getLocation()); 317 return this.vread(resourceClass, resVersionedIdentifier.getId(),resVersionedIdentifier.getVersionId()); 318 } catch(ClassCastException e) { 319 // if we fall throught we have the correct type already in the create 320 } 321 322 return result.getPayload(); 323 } 324 325// 326// public <T extends Resource> boolean delete(Class<T> resourceClass, String id) { 327// try { 328// return utils.issueDeleteRequest(resourceAddress.resolveGetUriFromResourceClassAndId(resourceClass, id), proxy); 329// } catch(Exception e) { 330// throw new EFhirClientException("An error has occurred while trying to delete this resource", e); 331// } 332// 333// } 334 335// 336// public <T extends Resource> OperationOutcome create(Class<T> resourceClass, T resource) { 337// ResourceRequest<T> resourceRequest = null; 338// try { 339// List<Header> headers = null; 340// resourceRequest = utils.issuePostRequest(resourceAddress.resolveGetUriFromResourceClass(resourceClass),utils.getResourceAsByteArray(resource, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers, proxy); 341// resourceRequest.addSuccessStatus(201); 342// if(resourceRequest.isUnsuccessfulRequest()) { 343// throw new EFhirClientException("Server responded with HTTP error code " + resourceRequest.getHttpStatus(), (OperationOutcome)resourceRequest.getPayload()); 344// } 345// } catch(Exception e) { 346// handleException("An error has occurred while trying to create this resource", e); 347// } 348// OperationOutcome operationOutcome = null;; 349// try { 350// operationOutcome = (OperationOutcome)resourceRequest.getPayload(); 351// ResourceAddress.ResourceVersionedIdentifier resVersionedIdentifier = 352// ResourceAddress.parseCreateLocation(resourceRequest.getLocation()); 353// OperationOutcomeIssueComponent issue = operationOutcome.addIssue(); 354// issue.setSeverity(IssueSeverity.INFORMATION); 355// issue.setUserData(ResourceAddress.ResourceVersionedIdentifier.class.toString(), 356// resVersionedIdentifier); 357// return operationOutcome; 358// } catch(ClassCastException e) { 359// // some server (e.g. grahams) returns the resource directly 360// operationOutcome = new OperationOutcome(); 361// OperationOutcomeIssueComponent issue = operationOutcome.addIssue(); 362// issue.setSeverity(IssueSeverity.INFORMATION); 363// issue.setUserData(ResourceRequest.class.toString(), 364// resourceRequest.getPayload()); 365// return operationOutcome; 366// } 367// } 368 369// 370// public <T extends Resource> Bundle history(Calendar lastUpdate, Class<T> resourceClass, String id) { 371// Bundle history = null; 372// try { 373// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceId(resourceClass, id, lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 374// } catch (Exception e) { 375// handleException("An error has occurred while trying to retrieve history information for this resource", e); 376// } 377// return history; 378// } 379 380// 381// public <T extends Resource> Bundle history(Date lastUpdate, Class<T> resourceClass, String id) { 382// Bundle history = null; 383// try { 384// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceId(resourceClass, id, lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 385// } catch (Exception e) { 386// handleException("An error has occurred while trying to retrieve history information for this resource", e); 387// } 388// return history; 389// } 390// 391// 392// public <T extends Resource> Bundle history(Calendar lastUpdate, Class<T> resourceClass) { 393// Bundle history = null; 394// try { 395// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceType(resourceClass, lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 396// } catch (Exception e) { 397// handleException("An error has occurred while trying to retrieve history information for this resource type", e); 398// } 399// return history; 400// } 401// 402// 403// public <T extends Resource> Bundle history(Date lastUpdate, Class<T> resourceClass) { 404// Bundle history = null; 405// try { 406// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceType(resourceClass, lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 407// } catch (Exception e) { 408// handleException("An error has occurred while trying to retrieve history information for this resource type", e); 409// } 410// return history; 411// } 412// 413// 414// public <T extends Resource> Bundle history(Class<T> resourceClass) { 415// Bundle history = null; 416// try { 417// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceType(resourceClass, maxResultSetSize), getPreferredResourceFormat(), proxy); 418// } catch (Exception e) { 419// handleException("An error has occurred while trying to retrieve history information for this resource type", e); 420// } 421// return history; 422// } 423// 424// 425// public <T extends Resource> Bundle history(Class<T> resourceClass, String id) { 426// Bundle history = null; 427// try { 428// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceId(resourceClass, id, maxResultSetSize), getPreferredResourceFormat(), proxy); 429// } catch (Exception e) { 430// handleException("An error has occurred while trying to retrieve history information for this resource", e); 431// } 432// return history; 433// } 434// 435// 436// public <T extends Resource> Bundle history(Date lastUpdate) { 437// Bundle history = null; 438// try { 439// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForAllResources(lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 440// } catch (Exception e) { 441// handleException("An error has occurred while trying to retrieve history since last update",e); 442// } 443// return history; 444// } 445// 446// 447// public <T extends Resource> Bundle history(Calendar lastUpdate) { 448// Bundle history = null; 449// try { 450// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForAllResources(lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 451// } catch (Exception e) { 452// handleException("An error has occurred while trying to retrieve history since last update",e); 453// } 454// return history; 455// } 456// 457// 458// public <T extends Resource> Bundle history() { 459// Bundle history = null; 460// try { 461// history = utils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForAllResources(maxResultSetSize), getPreferredResourceFormat(), proxy); 462// } catch (Exception e) { 463// handleException("An error has occurred while trying to retrieve history since last update",e); 464// } 465// return history; 466// } 467// 468// 469// public <T extends Resource> Bundle search(Class<T> resourceClass, Map<String, String> parameters) { 470// Bundle searchResults = null; 471// try { 472// searchResults = utils.issueGetFeedRequest(resourceAddress.resolveSearchUri(resourceClass, parameters), getPreferredResourceFormat(), proxy); 473// } catch (Exception e) { 474// handleException("Error performing search with parameters " + parameters, e); 475// } 476// return searchResults; 477// } 478// 479// 480// public <T extends Resource> Bundle searchPost(Class<T> resourceClass, T resource, Map<String, String> parameters) { 481// Bundle searchResults = null; 482// try { 483// searchResults = utils.issuePostFeedRequest(resourceAddress.resolveSearchUri(resourceClass, new HashMap<String, String>()), parameters, "src", resource, getPreferredResourceFormat()); 484// } catch (Exception e) { 485// handleException("Error performing search with parameters " + parameters, e); 486// } 487// return searchResults; 488// } 489 490 491 public <T extends Resource> Parameters operateType(Class<T> resourceClass, String name, Parameters params) { 492 boolean complex = false; 493 for (ParametersParameterComponent p : params.getParameter()) 494 complex = complex || !(p.getValue() instanceof PrimitiveType); 495 Parameters searchResults = null; 496 String ps = ""; 497 try { 498 if (!complex) 499 for (ParametersParameterComponent p : params.getParameter()) 500 if (p.getValue() instanceof PrimitiveType) 501 ps += p.getName() + "=" + Utilities.encodeUri(((PrimitiveType) p.getValue()).asStringValue())+"&"; 502 ResourceRequest<T> result; 503 if (complex) 504 result = utils.issuePostRequest(resourceAddress.resolveOperationURLFromClass(resourceClass, name, ps), utils.getResourceAsByteArray(params, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat()); 505 else 506 result = utils.issueGetResourceRequest(resourceAddress.resolveOperationURLFromClass(resourceClass, name, ps), getPreferredResourceFormat()); 507 result.addErrorStatus(410);//gone 508 result.addErrorStatus(404);//unknown 509 result.addSuccessStatus(200);//Only one for now 510 if(result.isUnsuccessfulRequest()) 511 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 512 if (result.getPayload() instanceof Parameters) 513 return (Parameters) result.getPayload(); 514 else { 515 Parameters p_out = new Parameters(); 516 p_out.addParameter().setName("return").setResource(result.getPayload()); 517 return p_out; 518 } 519 } catch (Exception e) { 520 handleException("Error performing operation '"+name+"' with parameters " + ps, e); 521 } 522 return null; 523 } 524 525 526 public Bundle transaction(Bundle batch) { 527 Bundle transactionResult = null; 528 try { 529 transactionResult = utils.postBatchRequest(resourceAddress.getBaseServiceUri(), utils.getFeedAsByteArray(batch, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat()); 530 } catch (Exception e) { 531 handleException("An error occurred trying to process this transaction request", e); 532 } 533 return transactionResult; 534 } 535 536 @SuppressWarnings("unchecked") 537 538 public <T extends Resource> OperationOutcome validate(Class<T> resourceClass, T resource, String id) { 539 ResourceRequest<T> result = null; 540 try { 541 result = utils.issuePostRequest(resourceAddress.resolveValidateUri(resourceClass, id), utils.getResourceAsByteArray(resource, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat()); 542 result.addErrorStatus(400);//gone 543 result.addErrorStatus(422);//Unprocessable Entity 544 result.addSuccessStatus(200);//OK 545 if(result.isUnsuccessfulRequest()) { 546 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 547 } 548 } catch(Exception e) { 549 handleException("An error has occurred while trying to validate this resource", e); 550 } 551 return (OperationOutcome)result.getPayload(); 552 } 553 554 /* change to meta operations 555 556 public List<Coding> getAllTags() { 557 TagListRequest result = null; 558 try { 559 result = utils.issueGetRequestForTagList(resourceAddress.resolveGetAllTags(), getPreferredResourceFormat(), null, proxy); 560 } catch (Exception e) { 561 handleException("An error has occurred while trying to retrieve all tags", e); 562 } 563 return result.getPayload(); 564 } 565 566 567 public <T extends Resource> List<Coding> getAllTagsForResourceType(Class<T> resourceClass) { 568 TagListRequest result = null; 569 try { 570 result = utils.issueGetRequestForTagList(resourceAddress.resolveGetAllTagsForResourceType(resourceClass), getPreferredResourceFormat(), null, proxy); 571 } catch (Exception e) { 572 handleException("An error has occurred while trying to retrieve tags for this resource type", e); 573 } 574 return result.getPayload(); 575 } 576 577 578 public <T extends Resource> List<Coding> getTagsForReference(Class<T> resource, String id) { 579 TagListRequest result = null; 580 try { 581 result = utils.issueGetRequestForTagList(resourceAddress.resolveGetTagsForReference(resource, id), getPreferredResourceFormat(), null, proxy); 582 } catch (Exception e) { 583 handleException("An error has occurred while trying to retrieve tags for this resource", e); 584 } 585 return result.getPayload(); 586 } 587 588 589 public <T extends Resource> List<Coding> getTagsForResourceVersion(Class<T> resource, String id, String versionId) { 590 TagListRequest result = null; 591 try { 592 result = utils.issueGetRequestForTagList(resourceAddress.resolveGetTagsForResourceVersion(resource, id, versionId), getPreferredResourceFormat(), null, proxy); 593 } catch (Exception e) { 594 handleException("An error has occurred while trying to retrieve tags for this resource version", e); 595 } 596 return result.getPayload(); 597 } 598 599// 600// public <T extends Resource> boolean deleteTagsForReference(Class<T> resourceClass, String id) { 601// try { 602// return utils.issueDeleteRequest(resourceAddress.resolveGetTagsForReference(resourceClass, id), proxy); 603// } catch(Exception e) { 604// handleException("An error has occurred while trying to retrieve tags for this resource version", e); 605// throw new EFhirClientException("An error has occurred while trying to delete this resource", e); 606// } 607// 608// } 609// 610// 611// public <T extends Resource> boolean deleteTagsForResourceVersion(Class<T> resourceClass, String id, List<Coding> tags, String version) { 612// try { 613// return utils.issueDeleteRequest(resourceAddress.resolveGetTagsForResourceVersion(resourceClass, id, version), proxy); 614// } catch(Exception e) { 615// handleException("An error has occurred while trying to retrieve tags for this resource version", e); 616// throw new EFhirClientException("An error has occurred while trying to delete this resource", e); 617// } 618// } 619 620 621 public <T extends Resource> List<Coding> createTags(List<Coding> tags, Class<T> resourceClass, String id) { 622 TagListRequest request = null; 623 try { 624 request = utils.issuePostRequestForTagList(resourceAddress.resolveGetTagsForReference(resourceClass, id),utils.getTagListAsByteArray(tags, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), null, proxy); 625 request.addSuccessStatus(201); 626 request.addSuccessStatus(200); 627 if(request.isUnsuccessfulRequest()) { 628 throw new EFhirClientException("Server responded with HTTP error code " + request.getHttpStatus()); 629 } 630 } catch(Exception e) { 631 handleException("An error has occurred while trying to set tags for this resource", e); 632 } 633 return request.getPayload(); 634 } 635 636 637 public <T extends Resource> List<Coding> createTags(List<Coding> tags, Class<T> resourceClass, String id, String version) { 638 TagListRequest request = null; 639 try { 640 request = utils.issuePostRequestForTagList(resourceAddress.resolveGetTagsForResourceVersion(resourceClass, id, version),utils.getTagListAsByteArray(tags, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), null, proxy); 641 request.addSuccessStatus(201); 642 request.addSuccessStatus(200); 643 if(request.isUnsuccessfulRequest()) { 644 throw new EFhirClientException("Server responded with HTTP error code " + request.getHttpStatus()); 645 } 646 } catch(Exception e) { 647 handleException("An error has occurred while trying to set the tags for this resource version", e); 648 } 649 return request.getPayload(); 650 } 651 652 653 public <T extends Resource> List<Coding> deleteTags(List<Coding> tags, Class<T> resourceClass, String id, String version) { 654 TagListRequest request = null; 655 try { 656 request = utils.issuePostRequestForTagList(resourceAddress.resolveDeleteTagsForResourceVersion(resourceClass, id, version),utils.getTagListAsByteArray(tags, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), null, proxy); 657 request.addSuccessStatus(201); 658 request.addSuccessStatus(200); 659 if(request.isUnsuccessfulRequest()) { 660 throw new EFhirClientException("Server responded with HTTP error code " + request.getHttpStatus()); 661 } 662 } catch(Exception e) { 663 handleException("An error has occurred while trying to delete the tags for this resource version", e); 664 } 665 return request.getPayload(); 666 } 667 */ 668 669 /** 670 * Helper method to prevent nesting of previously thrown EFhirClientExceptions 671 * 672 * @param e 673 * @throws EFhirClientException 674 */ 675 protected void handleException(String message, Exception e) throws EFhirClientException { 676 if(e instanceof EFhirClientException) { 677 throw (EFhirClientException)e; 678 } else { 679 throw new EFhirClientException(message, e); 680 } 681 } 682 683 /** 684 * Helper method to determine whether desired resource representation 685 * is Json or XML. 686 * 687 * @param format 688 * @return 689 */ 690 protected boolean isJson(String format) { 691 boolean isJson = false; 692 if(format.toLowerCase().contains("json")) { 693 isJson = true; 694 } 695 return isJson; 696 } 697 698 public Bundle fetchFeed(String url) { 699 Bundle feed = null; 700 try { 701 feed = utils.issueGetFeedRequest(new URI(url), getPreferredResourceFormat()); 702 } catch (Exception e) { 703 handleException("An error has occurred while trying to retrieve history since last update",e); 704 } 705 return feed; 706 } 707 708 public ValueSet expandValueset(ValueSet source, Parameters expParams) { 709 List<Header> headers = null; 710 Parameters p = expParams == null ? new Parameters() : expParams.copy(); 711 p.addParameter().setName("valueSet").setResource(source); 712 ResourceRequest<Resource> result = utils.issuePostRequest(resourceAddress.resolveOperationUri(ValueSet.class, "expand"), 713 utils.getResourceAsByteArray(p, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers); 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 Parameters lookupCode(Map<String, String> params) { 728 ResourceRequest<Resource> result = utils.issueGetResourceRequest(resourceAddress.resolveOperationUri(CodeSystem.class, "lookup", params), getPreferredResourceFormat()); 729 result.addErrorStatus(410);//gone 730 result.addErrorStatus(404);//unknown 731 result.addErrorStatus(405); 732 result.addErrorStatus(422);//Unprocessable Entity 733 result.addSuccessStatus(200); 734 result.addSuccessStatus(201); 735 if(result.isUnsuccessfulRequest()) { 736 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 737 } 738 return (Parameters) result.getPayload(); 739 } 740 public ValueSet expandValueset(ValueSet source, Parameters expParams, Map<String, String> params) { 741 List<Header> headers = null; 742 Parameters p = expParams == null ? new Parameters() : expParams.copy(); 743 p.addParameter().setName("valueSet").setResource(source); 744 for (String n : params.keySet()) 745 p.addParameter().setName(n).setValue(new StringType(params.get(n))); 746 ResourceRequest<Resource> result = utils.issuePostRequest(resourceAddress.resolveOperationUri(ValueSet.class, "expand", params), 747 utils.getResourceAsByteArray(p, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers); 748 result.addErrorStatus(410);//gone 749 result.addErrorStatus(404);//unknown 750 result.addErrorStatus(405); 751 result.addErrorStatus(422);//Unprocessable Entity 752 result.addSuccessStatus(200); 753 result.addSuccessStatus(201); 754 if(result.isUnsuccessfulRequest()) { 755 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 756 } 757 return (ValueSet) result.getPayload(); 758 } 759 760// public ValueSet expandValueset(ValueSet source, ExpansionProfile profile, Map<String, String> params) { 761// List<Header> headers = null; 762// ResourceRequest<Resource> result = utils.issuePostRequest(resourceAddress.resolveOperationUri(ValueSet.class, "expand", params), 763// utils.getResourceAsByteArray(source, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers, proxy); 764// result.addErrorStatus(410);//gone 765// result.addErrorStatus(404);//unknown 766// result.addErrorStatus(405); 767// result.addErrorStatus(422);//Unprocessable Entity 768// result.addSuccessStatus(200); 769// result.addSuccessStatus(201); 770// if(result.isUnsuccessfulRequest()) { 771// throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 772// } 773// return (ValueSet) result.getPayload(); 774// } 775 776 777 public String getAddress() { 778 return base; 779 } 780 781 public ConceptMap initializeClosure(String name) { 782 Parameters params = new Parameters(); 783 params.addParameter().setName("name").setValue(new StringType(name)); 784 List<Header> headers = null; 785 ResourceRequest<Resource> result = utils.issuePostRequest(resourceAddress.resolveOperationUri(null, "closure", new HashMap<String, String>()), 786 utils.getResourceAsByteArray(params, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers); 787 result.addErrorStatus(410);//gone 788 result.addErrorStatus(404);//unknown 789 result.addErrorStatus(405); 790 result.addErrorStatus(422);//Unprocessable Entity 791 result.addSuccessStatus(200); 792 result.addSuccessStatus(201); 793 if(result.isUnsuccessfulRequest()) { 794 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 795 } 796 return (ConceptMap) result.getPayload(); 797 } 798 799 public ConceptMap updateClosure(String name, Coding coding) { 800 Parameters params = new Parameters(); 801 params.addParameter().setName("name").setValue(new StringType(name)); 802 params.addParameter().setName("concept").setValue(coding); 803 List<Header> headers = null; 804 ResourceRequest<Resource> result = utils.issuePostRequest(resourceAddress.resolveOperationUri(null, "closure", new HashMap<String, String>()), 805 utils.getResourceAsByteArray(params, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers); 806 result.addErrorStatus(410);//gone 807 result.addErrorStatus(404);//unknown 808 result.addErrorStatus(405); 809 result.addErrorStatus(422);//Unprocessable Entity 810 result.addSuccessStatus(200); 811 result.addSuccessStatus(201); 812 if(result.isUnsuccessfulRequest()) { 813 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 814 } 815 return (ConceptMap) result.getPayload(); 816 } 817 818 public int getTimeout() { 819 return utils.getTimeout(); 820 } 821 822 public void setTimeout(int timeout) { 823 utils.setTimeout(timeout); 824 } 825 826 public String getUsername() { 827 return utils.getUsername(); 828 } 829 830 public void setUsername(String username) { 831 utils.setUsername(username); 832 } 833 834 public String getPassword() { 835 return utils.getPassword(); 836 } 837 838 public void setPassword(String password) { 839 utils.setPassword(password); 840 } 841 842 public ToolingClientLogger getLogger() { 843 return utils.getLogger(); 844 } 845 846 public void setLogger(ToolingClientLogger logger) { 847 utils.setLogger(logger); 848 } 849 850 851}