001package org.hl7.fhir.dstu2.utils.client; 002 003/*- 004 * #%L 005 * org.hl7.fhir.dstu2 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.dstu2.model.Bundle; 063import org.hl7.fhir.dstu2.model.Coding; 064import org.hl7.fhir.dstu2.model.ConceptMap; 065import org.hl7.fhir.dstu2.model.Conformance; 066import org.hl7.fhir.dstu2.model.OperationOutcome; 067import org.hl7.fhir.dstu2.model.Parameters; 068import org.hl7.fhir.dstu2.model.Parameters.ParametersParameterComponent; 069import org.hl7.fhir.dstu2.model.PrimitiveType; 070import org.hl7.fhir.dstu2.model.Resource; 071import org.hl7.fhir.dstu2.model.StringType; 072import org.hl7.fhir.dstu2.model.ValueSet; 073import org.hl7.fhir.utilities.Utilities; 074 075/** 076 * Very Simple RESTful client. This is purely for use in the standalone 077 * tools jar packages. It doesn't support many features, only what the tools 078 * need. 079 * 080 * To use, initialize class and set base service URI as follows: 081 * 082 * <pre><code> 083 * FHIRSimpleClient fhirClient = new FHIRSimpleClient(); 084 * fhirClient.initialize("http://my.fhir.domain/myServiceRoot"); 085 * </code></pre> 086 * 087 * Default Accept and Content-Type headers are application/xml+fhir and application/j+fhir. 088 * 089 * These can be changed by invoking the following setter functions: 090 * 091 * <pre><code> 092 * setPreferredResourceFormat() 093 * setPreferredFeedFormat() 094 * </code></pre> 095 * 096 * TODO Review all sad paths. 097 * 098 * @author Claude Nanjo 099 * 100 */ 101public class FHIRToolingClient { 102 103 public static final String DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ssK"; 104 public static final String DATE_FORMAT = "yyyy-MM-dd"; 105 106 private String base; 107 private ResourceAddress resourceAddress; 108 private ResourceFormat preferredResourceFormat; 109 private HttpHost proxy; 110 private int maxResultSetSize = -1;//_count 111 private Conformance conf; 112 113 //Pass enpoint for client - URI 114 public FHIRToolingClient(String baseServiceUrl) throws URISyntaxException { 115 preferredResourceFormat = ResourceFormat.RESOURCE_XML; 116 initialize(baseServiceUrl); 117 } 118 119 public void configureProxy(String proxyHost, int proxyPort) { 120 proxy = new HttpHost(proxyHost, proxyPort); 121 } 122 123 public void initialize(String baseServiceUrl) throws URISyntaxException { 124 base = baseServiceUrl; 125 resourceAddress = new ResourceAddress(baseServiceUrl); 126 this.maxResultSetSize = -1; 127 checkConformance(); 128 } 129 130 private void checkConformance() { 131 try { 132 conf = getConformanceStatementQuick(); 133 } catch (Throwable e) { 134 } 135 } 136 137 public String getPreferredResourceFormat() { 138 return preferredResourceFormat.getHeader(); 139 } 140 141 public void setPreferredResourceFormat(ResourceFormat resourceFormat) { 142 preferredResourceFormat = resourceFormat; 143 } 144 145 public int getMaximumRecordCount() { 146 return maxResultSetSize; 147 } 148 149 public void setMaximumRecordCount(int maxResultSetSize) { 150 this.maxResultSetSize = maxResultSetSize; 151 } 152 153 public Conformance getConformanceStatement() throws EFhirClientException { 154 if (conf != null) 155 return conf; 156 return getConformanceStatement(false); 157 } 158 159 public Conformance getConformanceStatement(boolean useOptionsVerb) { 160 Conformance conformance = null; 161 try { 162 if(useOptionsVerb) { 163 conformance = (Conformance)ClientUtils.issueOptionsRequest(resourceAddress.getBaseServiceUri(), getPreferredResourceFormat(), proxy).getReference();//TODO fix this 164 } else { 165 conformance = (Conformance)ClientUtils.issueGetResourceRequest(resourceAddress.resolveMetadataUri(false), getPreferredResourceFormat(), proxy).getReference(); 166 } 167 } catch(Exception e) { 168 handleException("An error has occurred while trying to fetch the server's conformance statement", e); 169 } 170 return conformance; 171 } 172 173 public Conformance getConformanceStatementQuick() throws EFhirClientException { 174 if (conf != null) 175 return conf; 176 return getConformanceStatementQuick(false); 177 } 178 179 public Conformance getConformanceStatementQuick(boolean useOptionsVerb) { 180 Conformance conformance = null; 181 try { 182 if(useOptionsVerb) { 183 conformance = (Conformance)ClientUtils.issueOptionsRequest(resourceAddress.getBaseServiceUri(), getPreferredResourceFormat(), proxy).getReference();//TODO fix this 184 } else { 185 conformance = (Conformance)ClientUtils.issueGetResourceRequest(resourceAddress.resolveMetadataUri(true), getPreferredResourceFormat(), proxy).getReference(); 186 } 187 } catch(Exception e) { 188 handleException("An error has occurred while trying to fetch the server's conformance statement", e); 189 } 190 return conformance; 191 } 192 193 public <T extends Resource> T read(Class<T> resourceClass, String id) {//TODO Change this to AddressableResource 194 ResourceRequest<T> result = null; 195 try { 196 result = ClientUtils.issueGetResourceRequest(resourceAddress.resolveGetUriFromResourceClassAndId(resourceClass, id), getPreferredResourceFormat(), proxy); 197 result.addErrorStatus(410);//gone 198 result.addErrorStatus(404);//unknown 199 result.addSuccessStatus(200);//Only one for now 200 if(result.isUnsuccessfulRequest()) { 201 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 202 } 203 } catch (Exception e) { 204 handleException("An error has occurred while trying to read this resource", e); 205 } 206 return result.getPayload(); 207 } 208 209 public <T extends Resource> T vread(Class<T> resourceClass, String id, String version) { 210 ResourceRequest<T> result = null; 211 try { 212 result = ClientUtils.issueGetResourceRequest(resourceAddress.resolveGetUriFromResourceClassAndIdAndVersion(resourceClass, id, version), getPreferredResourceFormat(), proxy); 213 result.addErrorStatus(410);//gone 214 result.addErrorStatus(404);//unknown 215 result.addErrorStatus(405);//unknown 216 result.addSuccessStatus(200);//Only one for now 217 if(result.isUnsuccessfulRequest()) { 218 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 219 } 220 } catch (Exception e) { 221 handleException("An error has occurred while trying to read this version of the resource", e); 222 } 223 return result.getPayload(); 224 } 225 226// 227// public <T extends Resource> T update(Class<T> resourceClass, T resource, String id) { 228// ResourceRequest<T> result = null; 229// try { 230// List<Header> headers = null; 231// result = ClientUtils.issuePutRequest(resourceAddress.resolveGetUriFromResourceClassAndId(resourceClass, id),ClientUtils.getResourceAsByteArray(resource, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers, proxy); 232// result.addErrorStatus(410);//gone 233// result.addErrorStatus(404);//unknown 234// result.addErrorStatus(405); 235// result.addErrorStatus(422);//Unprocessable Entity 236// result.addSuccessStatus(200); 237// result.addSuccessStatus(201); 238// if(result.isUnsuccessfulRequest()) { 239// throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 240// } 241// } catch(Exception e) { 242// throw new EFhirClientException("An error has occurred while trying to update this resource", e); 243// } 244// // 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 245// try { 246// OperationOutcome operationOutcome = (OperationOutcome)result.getPayload(); 247// ResourceAddress.ResourceVersionedIdentifier resVersionedIdentifier = ResourceAddress.parseCreateLocation(result.getLocation()); 248// return this.vread(resourceClass, resVersionedIdentifier.getId(),resVersionedIdentifier.getVersionId()); 249// } catch(ClassCastException e) { 250// // if we fall throught we have the correct type already in the create 251// } 252// 253// return result.getPayload(); 254// } 255 256// 257// public <T extends Resource> boolean delete(Class<T> resourceClass, String id) { 258// try { 259// return ClientUtils.issueDeleteRequest(resourceAddress.resolveGetUriFromResourceClassAndId(resourceClass, id), proxy); 260// } catch(Exception e) { 261// throw new EFhirClientException("An error has occurred while trying to delete this resource", e); 262// } 263// 264// } 265 266// 267// public <T extends Resource> OperationOutcome create(Class<T> resourceClass, T resource) { 268// ResourceRequest<T> resourceRequest = null; 269// try { 270// List<Header> headers = null; 271// resourceRequest = ClientUtils.issuePostRequest(resourceAddress.resolveGetUriFromResourceClass(resourceClass),ClientUtils.getResourceAsByteArray(resource, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers, proxy); 272// resourceRequest.addSuccessStatus(201); 273// if(resourceRequest.isUnsuccessfulRequest()) { 274// throw new EFhirClientException("Server responded with HTTP error code " + resourceRequest.getHttpStatus(), (OperationOutcome)resourceRequest.getPayload()); 275// } 276// } catch(Exception e) { 277// handleException("An error has occurred while trying to create this resource", e); 278// } 279// OperationOutcome operationOutcome = null;; 280// try { 281// operationOutcome = (OperationOutcome)resourceRequest.getPayload(); 282// ResourceAddress.ResourceVersionedIdentifier resVersionedIdentifier = 283// ResourceAddress.parseCreateLocation(resourceRequest.getLocation()); 284// OperationOutcomeIssueComponent issue = operationOutcome.addIssue(); 285// issue.setSeverity(IssueSeverity.INFORMATION); 286// issue.setUserData(ResourceAddress.ResourceVersionedIdentifier.class.toString(), 287// resVersionedIdentifier); 288// return operationOutcome; 289// } catch(ClassCastException e) { 290// // some server (e.g. grahams) returns the resource directly 291// operationOutcome = new OperationOutcome(); 292// OperationOutcomeIssueComponent issue = operationOutcome.addIssue(); 293// issue.setSeverity(IssueSeverity.INFORMATION); 294// issue.setUserData(ResourceRequest.class.toString(), 295// resourceRequest.getPayload()); 296// return operationOutcome; 297// } 298// } 299 300// 301// public <T extends Resource> Bundle history(Calendar lastUpdate, Class<T> resourceClass, String id) { 302// Bundle history = null; 303// try { 304// history = ClientUtils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceId(resourceClass, id, lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 305// } catch (Exception e) { 306// handleException("An error has occurred while trying to retrieve history information for this resource", e); 307// } 308// return history; 309// } 310 311// 312// public <T extends Resource> Bundle history(Date lastUpdate, Class<T> resourceClass, String id) { 313// Bundle history = null; 314// try { 315// history = ClientUtils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceId(resourceClass, id, lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 316// } catch (Exception e) { 317// handleException("An error has occurred while trying to retrieve history information for this resource", e); 318// } 319// return history; 320// } 321// 322// 323// public <T extends Resource> Bundle history(Calendar lastUpdate, Class<T> resourceClass) { 324// Bundle history = null; 325// try { 326// history = ClientUtils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceType(resourceClass, lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 327// } catch (Exception e) { 328// handleException("An error has occurred while trying to retrieve history information for this resource type", e); 329// } 330// return history; 331// } 332// 333// 334// public <T extends Resource> Bundle history(Date lastUpdate, Class<T> resourceClass) { 335// Bundle history = null; 336// try { 337// history = ClientUtils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceType(resourceClass, lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 338// } catch (Exception e) { 339// handleException("An error has occurred while trying to retrieve history information for this resource type", e); 340// } 341// return history; 342// } 343// 344// 345// public <T extends Resource> Bundle history(Class<T> resourceClass) { 346// Bundle history = null; 347// try { 348// history = ClientUtils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceType(resourceClass, maxResultSetSize), getPreferredResourceFormat(), proxy); 349// } catch (Exception e) { 350// handleException("An error has occurred while trying to retrieve history information for this resource type", e); 351// } 352// return history; 353// } 354// 355// 356// public <T extends Resource> Bundle history(Class<T> resourceClass, String id) { 357// Bundle history = null; 358// try { 359// history = ClientUtils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForResourceId(resourceClass, id, maxResultSetSize), getPreferredResourceFormat(), proxy); 360// } catch (Exception e) { 361// handleException("An error has occurred while trying to retrieve history information for this resource", e); 362// } 363// return history; 364// } 365// 366// 367// public <T extends Resource> Bundle history(Date lastUpdate) { 368// Bundle history = null; 369// try { 370// history = ClientUtils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForAllResources(lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 371// } catch (Exception e) { 372// handleException("An error has occurred while trying to retrieve history since last update",e); 373// } 374// return history; 375// } 376// 377// 378// public <T extends Resource> Bundle history(Calendar lastUpdate) { 379// Bundle history = null; 380// try { 381// history = ClientUtils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForAllResources(lastUpdate, maxResultSetSize), getPreferredResourceFormat(), proxy); 382// } catch (Exception e) { 383// handleException("An error has occurred while trying to retrieve history since last update",e); 384// } 385// return history; 386// } 387// 388// 389// public <T extends Resource> Bundle history() { 390// Bundle history = null; 391// try { 392// history = ClientUtils.issueGetFeedRequest(resourceAddress.resolveGetHistoryForAllResources(maxResultSetSize), getPreferredResourceFormat(), proxy); 393// } catch (Exception e) { 394// handleException("An error has occurred while trying to retrieve history since last update",e); 395// } 396// return history; 397// } 398// 399// 400// public <T extends Resource> Bundle search(Class<T> resourceClass, Map<String, String> parameters) { 401// Bundle searchResults = null; 402// try { 403// searchResults = ClientUtils.issueGetFeedRequest(resourceAddress.resolveSearchUri(resourceClass, parameters), getPreferredResourceFormat(), proxy); 404// } catch (Exception e) { 405// handleException("Error performing search with parameters " + parameters, e); 406// } 407// return searchResults; 408// } 409// 410// 411// public <T extends Resource> Bundle searchPost(Class<T> resourceClass, T resource, Map<String, String> parameters) { 412// Bundle searchResults = null; 413// try { 414// searchResults = ClientUtils.issuePostFeedRequest(resourceAddress.resolveSearchUri(resourceClass, new HashMap<String, String>()), parameters, "src", resource, getPreferredResourceFormat()); 415// } catch (Exception e) { 416// handleException("Error performing search with parameters " + parameters, e); 417// } 418// return searchResults; 419// } 420 421 422 public <T extends Resource> Parameters operateType(Class<T> resourceClass, String name, Parameters params) { 423 boolean complex = false; 424 for (ParametersParameterComponent p : params.getParameter()) 425 complex = complex || !(p.getValue() instanceof PrimitiveType); 426 Parameters searchResults = null; 427 String ps = ""; 428 try { 429 if (!complex) 430 for (ParametersParameterComponent p : params.getParameter()) 431 if (p.getValue() instanceof PrimitiveType) 432 ps += p.getName() + "=" + Utilities.encodeUri(((PrimitiveType) p.getValue()).asStringValue())+"&"; 433 ResourceRequest<T> result; 434 if (complex) 435 result = ClientUtils.issuePostRequest(resourceAddress.resolveOperationURLFromClass(resourceClass, name, ps), ClientUtils.getResourceAsByteArray(params, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), proxy); 436 else 437 result = ClientUtils.issueGetResourceRequest(resourceAddress.resolveOperationURLFromClass(resourceClass, name, ps), getPreferredResourceFormat(), proxy); 438 result.addErrorStatus(410);//gone 439 result.addErrorStatus(404);//unknown 440 result.addSuccessStatus(200);//Only one for now 441 if(result.isUnsuccessfulRequest()) 442 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 443 if (result.getPayload() instanceof Parameters) 444 return (Parameters) result.getPayload(); 445 else { 446 Parameters p_out = new Parameters(); 447 p_out.addParameter().setName("return").setResource(result.getPayload()); 448 return p_out; 449 } 450 } catch (Exception e) { 451 handleException("Error performing operation '"+name+"' with parameters " + ps, e); 452 } 453 return null; 454 } 455 456 457 public Bundle transaction(Bundle batch) { 458 Bundle transactionResult = null; 459 try { 460 transactionResult = ClientUtils.postBatchRequest(resourceAddress.getBaseServiceUri(), ClientUtils.getFeedAsByteArray(batch, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), proxy); 461 } catch (Exception e) { 462 handleException("An error occurred trying to process this transaction request", e); 463 } 464 return transactionResult; 465 } 466 467 @SuppressWarnings("unchecked") 468 469 public <T extends Resource> OperationOutcome validate(Class<T> resourceClass, T resource, String id) { 470 ResourceRequest<T> result = null; 471 try { 472 result = ClientUtils.issuePostRequest(resourceAddress.resolveValidateUri(resourceClass, id), ClientUtils.getResourceAsByteArray(resource, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), proxy); 473 result.addErrorStatus(400);//gone 474 result.addErrorStatus(422);//Unprocessable Entity 475 result.addSuccessStatus(200);//OK 476 if(result.isUnsuccessfulRequest()) { 477 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 478 } 479 } catch(Exception e) { 480 handleException("An error has occurred while trying to validate this resource", e); 481 } 482 return (OperationOutcome)result.getPayload(); 483 } 484 485 /* change to meta operations 486 487 public List<Coding> getAllTags() { 488 TagListRequest result = null; 489 try { 490 result = ClientUtils.issueGetRequestForTagList(resourceAddress.resolveGetAllTags(), getPreferredResourceFormat(), null, proxy); 491 } catch (Exception e) { 492 handleException("An error has occurred while trying to retrieve all tags", e); 493 } 494 return result.getPayload(); 495 } 496 497 498 public <T extends Resource> List<Coding> getAllTagsForResourceType(Class<T> resourceClass) { 499 TagListRequest result = null; 500 try { 501 result = ClientUtils.issueGetRequestForTagList(resourceAddress.resolveGetAllTagsForResourceType(resourceClass), getPreferredResourceFormat(), null, proxy); 502 } catch (Exception e) { 503 handleException("An error has occurred while trying to retrieve tags for this resource type", e); 504 } 505 return result.getPayload(); 506 } 507 508 509 public <T extends Resource> List<Coding> getTagsForReference(Class<T> resource, String id) { 510 TagListRequest result = null; 511 try { 512 result = ClientUtils.issueGetRequestForTagList(resourceAddress.resolveGetTagsForReference(resource, id), getPreferredResourceFormat(), null, proxy); 513 } catch (Exception e) { 514 handleException("An error has occurred while trying to retrieve tags for this resource", e); 515 } 516 return result.getPayload(); 517 } 518 519 520 public <T extends Resource> List<Coding> getTagsForResourceVersion(Class<T> resource, String id, String versionId) { 521 TagListRequest result = null; 522 try { 523 result = ClientUtils.issueGetRequestForTagList(resourceAddress.resolveGetTagsForResourceVersion(resource, id, versionId), getPreferredResourceFormat(), null, proxy); 524 } catch (Exception e) { 525 handleException("An error has occurred while trying to retrieve tags for this resource version", e); 526 } 527 return result.getPayload(); 528 } 529 530// 531// public <T extends Resource> boolean deleteTagsForReference(Class<T> resourceClass, String id) { 532// try { 533// return ClientUtils.issueDeleteRequest(resourceAddress.resolveGetTagsForReference(resourceClass, id), proxy); 534// } catch(Exception e) { 535// handleException("An error has occurred while trying to retrieve tags for this resource version", e); 536// throw new EFhirClientException("An error has occurred while trying to delete this resource", e); 537// } 538// 539// } 540// 541// 542// public <T extends Resource> boolean deleteTagsForResourceVersion(Class<T> resourceClass, String id, List<Coding> tags, String version) { 543// try { 544// return ClientUtils.issueDeleteRequest(resourceAddress.resolveGetTagsForResourceVersion(resourceClass, id, version), proxy); 545// } catch(Exception e) { 546// handleException("An error has occurred while trying to retrieve tags for this resource version", e); 547// throw new EFhirClientException("An error has occurred while trying to delete this resource", e); 548// } 549// } 550 551 552 public <T extends Resource> List<Coding> createTags(List<Coding> tags, Class<T> resourceClass, String id) { 553 TagListRequest request = null; 554 try { 555 request = ClientUtils.issuePostRequestForTagList(resourceAddress.resolveGetTagsForReference(resourceClass, id),ClientUtils.getTagListAsByteArray(tags, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), null, proxy); 556 request.addSuccessStatus(201); 557 request.addSuccessStatus(200); 558 if(request.isUnsuccessfulRequest()) { 559 throw new EFhirClientException("Server responded with HTTP error code " + request.getHttpStatus()); 560 } 561 } catch(Exception e) { 562 handleException("An error has occurred while trying to set tags for this resource", e); 563 } 564 return request.getPayload(); 565 } 566 567 568 public <T extends Resource> List<Coding> createTags(List<Coding> tags, Class<T> resourceClass, String id, String version) { 569 TagListRequest request = null; 570 try { 571 request = ClientUtils.issuePostRequestForTagList(resourceAddress.resolveGetTagsForResourceVersion(resourceClass, id, version),ClientUtils.getTagListAsByteArray(tags, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), null, proxy); 572 request.addSuccessStatus(201); 573 request.addSuccessStatus(200); 574 if(request.isUnsuccessfulRequest()) { 575 throw new EFhirClientException("Server responded with HTTP error code " + request.getHttpStatus()); 576 } 577 } catch(Exception e) { 578 handleException("An error has occurred while trying to set the tags for this resource version", e); 579 } 580 return request.getPayload(); 581 } 582 583 584 public <T extends Resource> List<Coding> deleteTags(List<Coding> tags, Class<T> resourceClass, String id, String version) { 585 TagListRequest request = null; 586 try { 587 request = ClientUtils.issuePostRequestForTagList(resourceAddress.resolveDeleteTagsForResourceVersion(resourceClass, id, version),ClientUtils.getTagListAsByteArray(tags, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), null, proxy); 588 request.addSuccessStatus(201); 589 request.addSuccessStatus(200); 590 if(request.isUnsuccessfulRequest()) { 591 throw new EFhirClientException("Server responded with HTTP error code " + request.getHttpStatus()); 592 } 593 } catch(Exception e) { 594 handleException("An error has occurred while trying to delete the tags for this resource version", e); 595 } 596 return request.getPayload(); 597 } 598 */ 599 600 /** 601 * Helper method to prevent nesting of previously thrown EFhirClientExceptions 602 * 603 * @param e 604 * @throws EFhirClientException 605 */ 606 protected void handleException(String message, Exception e) throws EFhirClientException { 607 if(e instanceof EFhirClientException) { 608 throw (EFhirClientException)e; 609 } else { 610 throw new EFhirClientException(message, e); 611 } 612 } 613 614 /** 615 * Helper method to determine whether desired resource representation 616 * is Json or XML. 617 * 618 * @param format 619 * @return 620 */ 621 protected boolean isJson(String format) { 622 boolean isJson = false; 623 if(format.toLowerCase().contains("json")) { 624 isJson = true; 625 } 626 return isJson; 627 } 628 629 public Bundle fetchFeed(String url) { 630 Bundle feed = null; 631 try { 632 feed = ClientUtils.issueGetFeedRequest(new URI(url), getPreferredResourceFormat(), proxy); 633 } catch (Exception e) { 634 handleException("An error has occurred while trying to retrieve history since last update",e); 635 } 636 return feed; 637 } 638 639 public ValueSet expandValueset(ValueSet source) { 640 List<Header> headers = null; 641 ResourceRequest<Resource> result = ClientUtils.issuePostRequest(resourceAddress.resolveOperationUri(ValueSet.class, "expand"), 642 ClientUtils.getResourceAsByteArray(source, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers, proxy); 643 result.addErrorStatus(410);//gone 644 result.addErrorStatus(404);//unknown 645 result.addErrorStatus(405); 646 result.addErrorStatus(422);//Unprocessable Entity 647 result.addSuccessStatus(200); 648 result.addSuccessStatus(201); 649 if(result.isUnsuccessfulRequest()) { 650 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 651 } 652 return (ValueSet) result.getPayload(); 653 } 654 655 656 public Parameters lookupCode(Map<String, String> params) { 657 ResourceRequest<Resource> result = ClientUtils.issueGetResourceRequest(resourceAddress.resolveOperationUri(ValueSet.class, "lookup", params), getPreferredResourceFormat(), proxy); 658 result.addErrorStatus(410);//gone 659 result.addErrorStatus(404);//unknown 660 result.addErrorStatus(405); 661 result.addErrorStatus(422);//Unprocessable Entity 662 result.addSuccessStatus(200); 663 result.addSuccessStatus(201); 664 if(result.isUnsuccessfulRequest()) { 665 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 666 } 667 return (Parameters) result.getPayload(); 668 } 669 public ValueSet expandValueset(ValueSet source, Parameters expParams,Map<String, String> params) { 670 List<Header> headers = null; 671 672 Parameters p = expParams == null ? new Parameters() : expParams.copy(); 673 p.addParameter().setName("valueSet").setResource(source); 674 for (String n : params.keySet()) 675 p.addParameter().setName(n).setValue(new StringType(params.get(n))); 676 677 ResourceRequest<Resource> result = ClientUtils.issuePostRequest(resourceAddress.resolveOperationUri(ValueSet.class, "expand", params), 678 ClientUtils.getResourceAsByteArray(p, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers, proxy); 679 result.addErrorStatus(410); //gone 680 result.addErrorStatus(404); //unknown 681 result.addErrorStatus(405); 682 result.addErrorStatus(422); //Unprocessable Entity 683 result.addSuccessStatus(200); 684 result.addSuccessStatus(201); 685 if(result.isUnsuccessfulRequest()) { 686 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 687 } 688 return (ValueSet) result.getPayload(); 689 } 690 691 692 public String getAddress() { 693 return base; 694 } 695 696 public ConceptMap initializeClosure(String name) { 697 Parameters params = new Parameters(); 698 params.addParameter().setName("name").setValue(new StringType(name)); 699 List<Header> headers = null; 700 ResourceRequest<Resource> result = ClientUtils.issuePostRequest(resourceAddress.resolveOperationUri(null, "closure", new HashMap<String, String>()), 701 ClientUtils.getResourceAsByteArray(params, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers, proxy); 702 result.addErrorStatus(410);//gone 703 result.addErrorStatus(404);//unknown 704 result.addErrorStatus(405); 705 result.addErrorStatus(422);//Unprocessable Entity 706 result.addSuccessStatus(200); 707 result.addSuccessStatus(201); 708 if(result.isUnsuccessfulRequest()) { 709 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 710 } 711 return (ConceptMap) result.getPayload(); 712 } 713 714 public ConceptMap updateClosure(String name, Coding coding) { 715 Parameters params = new Parameters(); 716 params.addParameter().setName("name").setValue(new StringType(name)); 717 params.addParameter().setName("concept").setValue(coding); 718 List<Header> headers = null; 719 ResourceRequest<Resource> result = ClientUtils.issuePostRequest(resourceAddress.resolveOperationUri(null, "closure", new HashMap<String, String>()), 720 ClientUtils.getResourceAsByteArray(params, false, isJson(getPreferredResourceFormat())), getPreferredResourceFormat(), headers, proxy); 721 result.addErrorStatus(410);//gone 722 result.addErrorStatus(404);//unknown 723 result.addErrorStatus(405); 724 result.addErrorStatus(422);//Unprocessable Entity 725 result.addSuccessStatus(200); 726 result.addSuccessStatus(201); 727 if(result.isUnsuccessfulRequest()) { 728 throw new EFhirClientException("Server returned error code " + result.getHttpStatus(), (OperationOutcome)result.getPayload()); 729 } 730 return (ConceptMap) result.getPayload(); 731 } 732 733 public Parameters getTerminologyCapabilities() { 734 return (Parameters) ClientUtils.issueGetResourceRequest(resourceAddress.resolveMetadataTxCaps(), getPreferredResourceFormat(), proxy).getReference(); 735 } 736 737}