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