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