001package org.hl7.fhir.r4.context; 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 032 033 034import java.util.List; 035import java.util.Locale; 036import java.util.Map; 037import java.util.Set; 038 039import org.fhir.ucum.UcumService; 040import org.hl7.fhir.exceptions.DefinitionException; 041import org.hl7.fhir.exceptions.FHIRException; 042import org.hl7.fhir.exceptions.TerminologyServiceException; 043import org.hl7.fhir.r4.formats.IParser; 044import org.hl7.fhir.r4.formats.ParserType; 045import org.hl7.fhir.r4.model.CodeSystem; 046import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent; 047import org.hl7.fhir.r4.model.CodeableConcept; 048import org.hl7.fhir.r4.model.Coding; 049import org.hl7.fhir.r4.model.ConceptMap; 050import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionBindingComponent; 051import org.hl7.fhir.r4.model.MetadataResource; 052import org.hl7.fhir.r4.model.Parameters; 053import org.hl7.fhir.r4.model.Resource; 054import org.hl7.fhir.r4.model.StructureDefinition; 055import org.hl7.fhir.r4.model.StructureMap; 056import org.hl7.fhir.r4.model.ValueSet; 057import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent; 058import org.hl7.fhir.r4.terminologies.ValueSetExpander.TerminologyServiceErrorClass; 059import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome; 060import org.hl7.fhir.r4.utils.INarrativeGenerator; 061import org.hl7.fhir.r4.utils.IResourceValidator; 062import org.hl7.fhir.utilities.TerminologyServiceOptions; 063import org.hl7.fhir.utilities.TranslationServices; 064import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; 065import org.hl7.fhir.utilities.validation.ValidationOptions; 066 067 068/** 069 * This is the standard interface used for access to underlying FHIR 070 * services through the tools and utilities provided by the reference 071 * implementation. 072 * 073 * The functionality it provides is 074 * - get access to parsers, validators, narrative builders etc 075 * (you can't create these directly because they need access 076 * to the right context for their information) 077 * 078 * - find resources that the tools need to carry out their tasks 079 * 080 * - provide access to terminology services they need. 081 * (typically, these terminology service requests are just 082 * passed through to the local implementation's terminology 083 * service) 084 * 085 * @author Grahame 086 */ 087public interface IWorkerContext { 088 089 /** 090 * Get the versions of the definitions loaded in context 091 * @return 092 */ 093 public String getVersion(); 094 095 // get the UCUM service (might not be available) 096 public UcumService getUcumService(); 097 098 // -- Parsers (read and write instances) ---------------------------------------- 099 100 101 /** 102 * Get a parser to read/write instances. Use the defined type (will be extended 103 * as further types are added, though the only currently anticipate type is RDF) 104 * 105 * XML/JSON - the standard renderers 106 * XHTML - render the narrative only (generate it if necessary) 107 * 108 * @param type 109 * @return 110 */ 111 public IParser getParser(ParserType type); 112 113 /** 114 * Get a parser to read/write instances. Determine the type 115 * from the stated type. Supported value for type: 116 * - the recommended MIME types 117 * - variants of application/xml and application/json 118 * - _format values xml, json 119 * 120 * @param type 121 * @return 122 */ 123 public IParser getParser(String type); 124 125 /** 126 * Get a JSON parser 127 * 128 * @return 129 */ 130 public IParser newJsonParser(); 131 132 /** 133 * Get an XML parser 134 * 135 * @return 136 */ 137 public IParser newXmlParser(); 138 139 /** 140 * Get a generator that can generate narrative for the instance 141 * 142 * @return a prepared generator 143 */ 144 public INarrativeGenerator getNarrativeGenerator(String prefix, String basePath); 145 146 /** 147 * Get a validator that can check whether a resource is valid 148 * 149 * @return a prepared generator 150 * @throws FHIRException 151 * @ 152 */ 153 public IResourceValidator newValidator() throws FHIRException; 154 155 // -- resource fetchers --------------------------------------------------- 156 157 /** 158 * Find an identified resource. The most common use of this is to access the the 159 * standard conformance resources that are part of the standard - structure 160 * definitions, value sets, concept maps, etc. 161 * 162 * Also, the narrative generator uses this, and may access any kind of resource 163 * 164 * The URI is called speculatively for things that might exist, so not finding 165 * a matching resouce, return null, not an error 166 * 167 * The URI can have one of 3 formats: 168 * - a full URL e.g. http://acme.org/fhir/ValueSet/[id] 169 * - a relative URL e.g. ValueSet/[id] 170 * - a logical id e.g. [id] 171 * 172 * It's an error if the second form doesn't agree with class_. It's an 173 * error if class_ is null for the last form 174 * 175 * @param resource 176 * @param Reference 177 * @return 178 * @throws FHIRException 179 * @throws Exception 180 */ 181 public <T extends Resource> T fetchResource(Class<T> class_, String uri); 182 public <T extends Resource> T fetchResourceWithException(Class<T> class_, String uri) throws FHIRException; 183 184 /** 185 * Variation of fetchResource when you have a string type, and don't need the right class 186 * 187 * The URI can have one of 3 formats: 188 * - a full URL e.g. http://acme.org/fhir/ValueSet/[id] 189 * - a relative URL e.g. ValueSet/[id] 190 * - a logical id e.g. [id] 191 * 192 * if type == null, the URI can't be a simple logical id 193 * 194 * @param type 195 * @param uri 196 * @return 197 */ 198 public Resource fetchResourceById(String type, String uri); 199 200 /** 201 * find whether a resource is available. 202 * 203 * Implementations of the interface can assume that if hasResource ruturns 204 * true, the resource will usually be fetched subsequently 205 * 206 * @param class_ 207 * @param uri 208 * @return 209 */ 210 public <T extends Resource> boolean hasResource(Class<T> class_, String uri); 211 212 /** 213 * cache a resource for later retrieval using fetchResource. 214 * 215 * Note that various context implementations will have their own ways of loading 216 * rseources, and not all need implement cacheResource 217 * @param res 218 * @throws FHIRException 219 */ 220 public void cacheResource(Resource res) throws FHIRException; 221 222 // -- profile services --------------------------------------------------------- 223 224 public List<String> getResourceNames(); 225 public Set<String> getResourceNamesAsSet(); 226 public List<String> getTypeNames(); 227 public List<StructureDefinition> allStructures(); // ensure snapshot exists... 228 public List<StructureDefinition> getStructures(); 229 public List<MetadataResource> allConformanceResources(); 230 public void generateSnapshot(StructureDefinition p) throws DefinitionException, FHIRException; 231 232 // -- Terminology services ------------------------------------------------------ 233 234 public Parameters getExpansionParameters(); 235 public void setExpansionProfile(Parameters expParameters); 236 237 // these are the terminology services used internally by the tools 238 /** 239 * Find the code system definition for the nominated system uri. 240 * return null if there isn't one (then the tool might try 241 * supportsSystem) 242 * 243 * @param system 244 * @return 245 */ 246 public CodeSystem fetchCodeSystem(String system); 247 248 /** 249 * True if the underlying terminology service provider will do 250 * expansion and code validation for the terminology. Corresponds 251 * to the extension 252 * 253 * http://hl7.org/fhir/StructureDefinition/capabilitystatement-supported-system 254 * 255 * in the Conformance resource 256 * 257 * @param system 258 * @return 259 * @throws Exception 260 */ 261 public boolean supportsSystem(String system) throws TerminologyServiceException; 262 263 /** 264 * find concept maps for a source 265 * @param url 266 * @return 267 * @throws FHIRException 268 */ 269 public List<ConceptMap> findMapsForSource(String url) throws FHIRException; 270 271 /** 272 * ValueSet Expansion - see $expand 273 * 274 * @param source 275 * @return 276 */ 277 public ValueSetExpansionOutcome expandVS(ValueSet source, boolean cacheOk, boolean heiarchical); 278 279 /** 280 * ValueSet Expansion - see $expand, but resolves the binding first 281 * 282 * @param source 283 * @return 284 * @throws FHIRException 285 */ 286 public ValueSetExpansionOutcome expandVS(ElementDefinitionBindingComponent binding, boolean cacheOk, boolean heiarchical) throws FHIRException; 287 /** 288 * Value set expanion inside the internal expansion engine - used 289 * for references to supported system (see "supportsSystem") for 290 * which there is no value set. 291 * 292 * @param inc 293 * @return 294 * @throws FHIRException 295 */ 296 public ValueSetExpansionOutcome expandVS(ConceptSetComponent inc, boolean heirarchical) throws TerminologyServiceException; 297 298 Locale getLocale(); 299 300 void setLocale(Locale locale); 301 302 String formatMessage(String theMessage, Object... theMessageArguments); 303 304 void setValidationMessageLanguage(Locale locale); 305 306 public class ValidationResult { 307 private ConceptDefinitionComponent definition; 308 private IssueSeverity severity; 309 private String message; 310 private TerminologyServiceErrorClass errorClass; 311 private String txLink; 312 313 public ValidationResult(IssueSeverity severity, String message) { 314 this.severity = severity; 315 this.message = message; 316 } 317 318 public ValidationResult(ConceptDefinitionComponent definition) { 319 this.definition = definition; 320 } 321 322 public ValidationResult(IssueSeverity severity, String message, ConceptDefinitionComponent definition) { 323 this.severity = severity; 324 this.message = message; 325 this.definition = definition; 326 } 327 328 public ValidationResult(IssueSeverity severity, String message, TerminologyServiceErrorClass errorClass) { 329 this.severity = severity; 330 this.message = message; 331 this.errorClass = errorClass; 332 } 333 334 public boolean isOk() { 335 return severity == null || severity == IssueSeverity.INFORMATION || severity == IssueSeverity.WARNING; 336 } 337 338 public String getDisplay() { 339// We don't want to return question-marks because that prevents something more useful from being displayed (e.g. the code) if there's no display value 340// return definition == null ? "??" : definition.getDisplay(); 341 return definition == null ? null : definition.getDisplay(); 342 } 343 344 public ConceptDefinitionComponent asConceptDefinition() { 345 return definition; 346 } 347 348 public IssueSeverity getSeverity() { 349 return severity; 350 } 351 352 public String getMessage() { 353 return message; 354 } 355 356 public boolean IsNoService() { 357 return errorClass == TerminologyServiceErrorClass.NOSERVICE; 358 } 359 360 public TerminologyServiceErrorClass getErrorClass() { 361 return errorClass; 362 } 363 364 public ValidationResult setSeverity(IssueSeverity severity) { 365 this.severity = severity; 366 return this; 367 } 368 369 public ValidationResult setMessage(String message) { 370 this.message = message; 371 return this; 372 } 373 374 public String getTxLink() { 375 return txLink; 376 } 377 378 public ValidationResult setTxLink(String txLink) { 379 this.txLink = txLink; 380 return this; 381 } 382 383 384 } 385 386 /** 387 * Validation of a code - consult the terminology service 388 * to see whether it is known. If known, return a description of it 389 * 390 * note: always return a result, with either an error or a code description 391 * 392 * corresponds to 2 terminology service calls: $validate-code and $lookup 393 * 394 * @param system 395 * @param code 396 * @param display 397 * @return 398 */ 399 public ValidationResult validateCode(ValidationOptions options, String system, String code, String display); 400 401 /** 402 * Validation of a code - consult the terminology service 403 * to see whether it is known. If known, return a description of it 404 * Also, check whether it's in the provided value set 405 * 406 * note: always return a result, with either an error or a code description, or both (e.g. known code, but not in the value set) 407 * 408 * corresponds to 2 terminology service calls: $validate-code and $lookup 409 * 410 * @param system 411 * @param code 412 * @param display 413 * @return 414 */ 415 public ValidationResult validateCode(ValidationOptions options, String system, String code, String display, ValueSet vs); 416 public ValidationResult validateCode(ValidationOptions options, String code, ValueSet vs); 417 public ValidationResult validateCode(ValidationOptions options, Coding code, ValueSet vs); 418 public ValidationResult validateCode(ValidationOptions options, CodeableConcept code, ValueSet vs); 419 420 /** 421 * Validation of a code - consult the terminology service 422 * to see whether it is known. If known, return a description of it 423 * Also, check whether it's in the provided value set fragment (for supported systems with no value set definition) 424 * 425 * note: always return a result, with either an error or a code description, or both (e.g. known code, but not in the value set) 426 * 427 * corresponds to 2 terminology service calls: $validate-code and $lookup 428 * 429 * @param system 430 * @param code 431 * @param display 432 * @return 433 */ 434 public ValidationResult validateCode(ValidationOptions options, String system, String code, String display, ConceptSetComponent vsi); 435 436 /** 437 * returns the recommended tla for the type 438 * 439 * @param name 440 * @return 441 */ 442 public String getAbbreviation(String name); 443 444 // return a set of types that have tails 445 public Set<String> typeTails(); 446 447 public String oid2Uri(String code); 448 449 public boolean hasCache(); 450 451 public interface ILoggingService { 452 public enum LogCategory { 453 PROGRESS, TX, INIT, CONTEXT, HTML 454 } 455 public void logMessage(String message); // status messages, always display 456 public void logDebugMessage(LogCategory category, String message); // verbose; only when debugging 457 } 458 459 public void setLogger(ILoggingService logger); 460 public ILoggingService getLogger(); 461 462 public boolean isNoTerminologyServer(); 463 464 public TranslationServices translator(); 465 public List<StructureMap> listTransforms(); 466 public StructureMap getTransform(String url); 467 468 public String getOverrideVersionNs(); 469 public void setOverrideVersionNs(String value); 470 471 public StructureDefinition fetchTypeDefinition(String typeName); 472 473 public void setUcumService(UcumService ucumService); 474 475 public String getLinkForUrl(String corePath, String s); 476}