001package org.hl7.fhir.r5.hapi.ctx; 002 003import ca.uhn.fhir.context.FhirContext; 004import ca.uhn.fhir.context.support.ConceptValidationOptions; 005import ca.uhn.fhir.context.support.IValidationSupport; 006import ca.uhn.fhir.context.support.ValidationSupportContext; 007import ca.uhn.fhir.i18n.Msg; 008import ca.uhn.fhir.rest.api.Constants; 009import ca.uhn.fhir.sl.cache.Cache; 010import ca.uhn.fhir.sl.cache.CacheFactory; 011import ca.uhn.fhir.system.HapiSystemProperties; 012import org.apache.commons.lang3.Validate; 013import org.fhir.ucum.UcumService; 014import org.hl7.fhir.exceptions.FHIRException; 015import org.hl7.fhir.exceptions.TerminologyServiceException; 016import org.hl7.fhir.r5.context.IContextResourceLoader; 017import org.hl7.fhir.r5.context.IWorkerContext; 018import org.hl7.fhir.r5.context.IWorkerContextManager; 019import org.hl7.fhir.r5.model.CodeSystem; 020import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent; 021import org.hl7.fhir.r5.model.CodeableConcept; 022import org.hl7.fhir.r5.model.Coding; 023import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent; 024import org.hl7.fhir.r5.model.NamingSystem; 025import org.hl7.fhir.r5.model.PackageInformation; 026import org.hl7.fhir.r5.model.Parameters; 027import org.hl7.fhir.r5.model.Resource; 028import org.hl7.fhir.r5.model.ResourceType; 029import org.hl7.fhir.r5.model.StructureDefinition; 030import org.hl7.fhir.r5.model.ValueSet; 031import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent; 032import org.hl7.fhir.r5.profilemodel.PEBuilder; 033import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome; 034import org.hl7.fhir.r5.terminologies.utilities.CodingValidationRequest; 035import org.hl7.fhir.r5.terminologies.utilities.ValidationResult; 036import org.hl7.fhir.r5.utils.validation.IResourceValidator; 037import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier; 038import org.hl7.fhir.utilities.FhirPublication; 039import org.hl7.fhir.utilities.TimeTracker; 040import org.hl7.fhir.utilities.i18n.I18nBase; 041import org.hl7.fhir.utilities.npm.BasePackageCacheManager; 042import org.hl7.fhir.utilities.npm.NpmPackage; 043import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; 044import org.hl7.fhir.utilities.validation.ValidationOptions; 045 046import java.io.FileNotFoundException; 047import java.io.IOException; 048import java.util.ArrayList; 049import java.util.Collections; 050import java.util.List; 051import java.util.Locale; 052import java.util.Map; 053import java.util.Set; 054 055import static org.apache.commons.lang3.StringUtils.isNotBlank; 056 057public final class HapiWorkerContext extends I18nBase implements IWorkerContext { 058 private final FhirContext myCtx; 059 private final Cache<String, Resource> myFetchedResourceCache; 060 private final IValidationSupport myValidationSupport; 061 private Parameters myExpansionProfile; 062 private String myOverrideVersionNs; 063 064 public HapiWorkerContext(FhirContext theCtx, IValidationSupport theValidationSupport) { 065 Validate.notNull(theCtx, "theCtx must not be null"); 066 Validate.notNull(theValidationSupport, "theValidationSupport must not be null"); 067 myCtx = theCtx; 068 myValidationSupport = theValidationSupport; 069 070 long timeoutMillis = HapiSystemProperties.getTestValidationResourceCachesMs(); 071 072 myFetchedResourceCache = CacheFactory.build(timeoutMillis); 073 074 // Set a default locale 075 setValidationMessageLanguage(getLocale()); 076 } 077 078 @Override 079 public CodeSystem fetchCodeSystem(String theSystem) { 080 if (myValidationSupport == null) { 081 return null; 082 } else { 083 return (CodeSystem) myValidationSupport.fetchCodeSystem(theSystem); 084 } 085 } 086 087 @Override 088 public CodeSystem fetchCodeSystem(String theSystem, String version) { 089 if (myValidationSupport == null) { 090 return null; 091 } else { 092 return (CodeSystem) myValidationSupport.fetchCodeSystem(theSystem); 093 } 094 } 095 096 @Override 097 public CodeSystem fetchCodeSystem(String system, FhirPublication fhirVersion) { 098 throw new UnsupportedOperationException(Msg.code(2456)); 099 } 100 101 @Override 102 public CodeSystem fetchCodeSystem(String system, String version, FhirPublication fhirVersion) { 103 throw new UnsupportedOperationException(Msg.code(2457)); 104 } 105 106 @Override 107 public CodeSystem fetchSupplementedCodeSystem(String theS) { 108 return null; 109 } 110 111 @Override 112 public CodeSystem fetchSupplementedCodeSystem(String theS, String theS1) { 113 return null; 114 } 115 116 @Override 117 public CodeSystem fetchSupplementedCodeSystem(String system, FhirPublication fhirVersion) { 118 throw new UnsupportedOperationException(Msg.code(2458)); 119 } 120 121 @Override 122 public CodeSystem fetchSupplementedCodeSystem(String system, String version, FhirPublication fhirVersion) { 123 throw new UnsupportedOperationException(Msg.code(2459)); 124 } 125 126 @Override 127 public List<String> getResourceNames() { 128 List<String> result = new ArrayList<>(); 129 for (ResourceType next : ResourceType.values()) { 130 result.add(next.name()); 131 } 132 Collections.sort(result); 133 return result; 134 } 135 136 @Override 137 public List<String> getResourceNames(FhirPublication fhirVersion) { 138 throw new UnsupportedOperationException(Msg.code(2460)); 139 } 140 141 @Override 142 public IResourceValidator newValidator() { 143 throw new UnsupportedOperationException(Msg.code(206)); 144 } 145 146 @Override 147 public Map<String, NamingSystem> getNSUrlMap() { 148 throw new UnsupportedOperationException(Msg.code(2241)); 149 } 150 151 @Override 152 public boolean supportsSystem(String theSystem) { 153 if (myValidationSupport == null) { 154 return false; 155 } else { 156 return myValidationSupport.isCodeSystemSupported( 157 new ValidationSupportContext(myValidationSupport), theSystem); 158 } 159 } 160 161 @Override 162 public boolean supportsSystem(String system, FhirPublication fhirVersion) throws TerminologyServiceException { 163 if (!fhirVersion.equals(FhirPublication.R5)) { 164 throw new UnsupportedOperationException(Msg.code(2461)); 165 } 166 return supportsSystem(system); 167 } 168 169 @Override 170 public ValidationResult validateCode(ValidationOptions theOptions, CodeableConcept theCode, ValueSet theVs) { 171 for (Coding next : theCode.getCoding()) { 172 ValidationResult retVal = validateCode(theOptions, next, theVs); 173 if (retVal.isOk()) { 174 return retVal; 175 } 176 } 177 178 return new ValidationResult(IssueSeverity.ERROR, null, null); 179 } 180 181 @Override 182 public ValidationResult validateCode(ValidationOptions theOptions, Coding theCode, ValueSet theVs) { 183 String system = theCode.getSystem(); 184 String code = theCode.getCode(); 185 String display = theCode.getDisplay(); 186 return validateCode(theOptions, system, null, code, display, theVs); 187 } 188 189 @Override 190 public ValidationResult validateCode( 191 ValidationOptions options, Coding code, ValueSet vs, ValidationContextCarrier ctxt) { 192 return validateCode(options, code, vs); 193 } 194 195 @Override 196 public void validateCodeBatch( 197 ValidationOptions options, List<? extends CodingValidationRequest> codes, ValueSet vs) { 198 throw new UnsupportedOperationException(Msg.code(209)); 199 } 200 201 @Override 202 public void validateCodeBatchByRef( 203 ValidationOptions validationOptions, List<? extends CodingValidationRequest> list, String s) { 204 throw new UnsupportedOperationException(Msg.code(2430)); 205 } 206 207 @Override 208 public ValueSetExpansionOutcome expandVS( 209 ValueSet theValueSet, boolean cacheOk, boolean heiarchical, boolean incompleteOk) { 210 return null; 211 } 212 213 @Override 214 public ValidationResult validateCode( 215 ValidationOptions theOptions, String theSystem, String theVersion, String theCode, String theDisplay) { 216 IValidationSupport.CodeValidationResult result = myValidationSupport.validateCode( 217 new ValidationSupportContext(myValidationSupport), 218 convertConceptValidationOptions(theOptions), 219 theSystem, 220 theCode, 221 theDisplay, 222 null); 223 if (result == null) { 224 return null; 225 } 226 IssueSeverity severity = null; 227 if (result.getSeverity() != null) { 228 severity = IssueSeverity.fromCode(result.getSeverityCode()); 229 } 230 ConceptDefinitionComponent definition = new ConceptDefinitionComponent().setCode(result.getCode()); 231 return new ValidationResult(severity, result.getMessage(), theSystem, theVersion, definition, null, null); 232 } 233 234 @Override 235 public ValidationResult validateCode( 236 ValidationOptions theOptions, 237 String theSystem, 238 String theVersion, 239 String theCode, 240 String theDisplay, 241 ValueSet theVs) { 242 IValidationSupport.CodeValidationResult outcome; 243 if (isNotBlank(theVs.getUrl())) { 244 outcome = myValidationSupport.validateCode( 245 new ValidationSupportContext(myValidationSupport), 246 convertConceptValidationOptions(theOptions), 247 theSystem, 248 theCode, 249 theDisplay, 250 theVs.getUrl()); 251 } else { 252 outcome = myValidationSupport.validateCodeInValueSet( 253 new ValidationSupportContext(myValidationSupport), 254 convertConceptValidationOptions(theOptions), 255 theSystem, 256 theCode, 257 theDisplay, 258 theVs); 259 } 260 261 if (outcome != null && outcome.isOk()) { 262 ConceptDefinitionComponent definition = new ConceptDefinitionComponent(); 263 definition.setCode(theCode); 264 definition.setDisplay(outcome.getDisplay()); 265 return new ValidationResult(theSystem, theVersion, definition, null); 266 } 267 268 return new ValidationResult( 269 IssueSeverity.ERROR, 270 "Unknown code[" + theCode + "] in system[" + Constants.codeSystemWithDefaultDescription(theSystem) 271 + "]", 272 null); 273 } 274 275 @Override 276 public ValidationResult validateCode(ValidationOptions theOptions, String code, ValueSet vs) { 277 return validateCode(theOptions, null, null, code, null, vs); 278 } 279 280 @Override 281 public Parameters getExpansionParameters() { 282 return myExpansionProfile; 283 } 284 285 @Override 286 public void setExpansionParameters(Parameters expParameters) { 287 setExpansionProfile(expParameters); 288 } 289 290 public void setExpansionProfile(Parameters theExpParameters) { 291 myExpansionProfile = theExpParameters; 292 } 293 294 @Override 295 public ValueSetExpansionOutcome expandVS(ValueSet theSource, boolean theCacheOk, boolean theHierarchical) { 296 throw new UnsupportedOperationException(Msg.code(2128)); 297 } 298 299 @Override 300 public ValueSetExpansionOutcome expandVS(ConceptSetComponent theInc, boolean theHierarchical, boolean theNoInactive) 301 throws TerminologyServiceException { 302 ValueSet input = new ValueSet(); 303 input.getCompose().setInactive(!theNoInactive); // TODO GGG/DO is this valid? 304 input.getCompose().addInclude(theInc); 305 IValidationSupport.ValueSetExpansionOutcome output = 306 myValidationSupport.expandValueSet(new ValidationSupportContext(myValidationSupport), null, input); 307 return new ValueSetExpansionOutcome( 308 (ValueSet) output.getValueSet(), output.getError(), null, output.getErrorIsFromServer()); 309 } 310 311 @Override 312 public Locale getLocale() { 313 return Locale.getDefault(); 314 } 315 316 @Override 317 public void setLocale(Locale locale) { 318 // ignore 319 } 320 321 @Override 322 public org.hl7.fhir.r5.context.ILoggingService getLogger() { 323 throw new UnsupportedOperationException(Msg.code(213)); 324 } 325 326 @Override 327 public void setLogger(org.hl7.fhir.r5.context.ILoggingService theLogger) { 328 throw new UnsupportedOperationException(Msg.code(214)); 329 } 330 331 @Override 332 public String getVersion() { 333 return myCtx.getVersion().getVersion().getFhirVersionString(); 334 } 335 336 @Override 337 public UcumService getUcumService() { 338 throw new UnsupportedOperationException(Msg.code(216)); 339 } 340 341 @Override 342 public void setUcumService(UcumService ucumService) { 343 throw new UnsupportedOperationException(Msg.code(217)); 344 } 345 346 @Override 347 public boolean isNoTerminologyServer() { 348 return false; 349 } 350 351 @Override 352 public Set<String> getCodeSystemsUsed() { 353 throw new UnsupportedOperationException(Msg.code(218)); 354 } 355 356 @Override 357 public StructureDefinition fetchTypeDefinition(String typeName) { 358 return fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + typeName); 359 } 360 361 @Override 362 public boolean isPrimitiveType(String s) { 363 throw new UnsupportedOperationException(Msg.code(2462)); 364 } 365 366 @Override 367 public boolean isDataType(String s) { 368 throw new UnsupportedOperationException(Msg.code(2463)); 369 } 370 371 @Override 372 public StructureDefinition fetchTypeDefinition(String typeName, FhirPublication fhirVersion) { 373 throw new UnsupportedOperationException(Msg.code(2464)); 374 } 375 376 @Override 377 public List<StructureDefinition> fetchTypeDefinitions(String n) { 378 throw new UnsupportedOperationException(Msg.code(234)); 379 } 380 381 @Override 382 public List<StructureDefinition> fetchTypeDefinitions(String n, FhirPublication fhirPublication) { 383 throw new UnsupportedOperationException(Msg.code(2465)); 384 } 385 386 @Override 387 public <T extends Resource> T fetchResourceRaw(Class<T> class_, String uri) { 388 return fetchResource(class_, uri); 389 } 390 391 @Override 392 public <T extends org.hl7.fhir.r5.model.Resource> T fetchResource(Class<T> theClass, String theUri) { 393 if (myValidationSupport == null || theUri == null) { 394 return null; 395 } else { 396 @SuppressWarnings("unchecked") 397 T retVal = (T) myFetchedResourceCache.get(theUri, t -> myValidationSupport.fetchResource(theClass, theUri)); 398 return retVal; 399 } 400 } 401 402 public <T extends Resource> T fetchResource(Class<T> class_, String uri, FhirPublication fhirVersion) { 403 throw new UnsupportedOperationException(Msg.code(2466)); 404 } 405 406 @Override 407 public <T extends org.hl7.fhir.r5.model.Resource> T fetchResourceWithException(Class<T> theClass, String theUri) 408 throws FHIRException { 409 T retVal = fetchResource(theClass, theUri); 410 if (retVal == null) { 411 throw new FHIRException(Msg.code(224) + "Could not find resource: " + theUri); 412 } 413 return retVal; 414 } 415 416 @Override 417 public <T extends Resource> T fetchResourceWithException(Class<T> theClass, String uri, Resource sourceOfReference) 418 throws FHIRException { 419 throw new UnsupportedOperationException(Msg.code(2213)); 420 } 421 422 @Override 423 public <T extends Resource> T fetchResource(Class<T> theClass, String theUri, String theVersion) { 424 return fetchResource(theClass, theUri + "|" + theVersion); 425 } 426 427 @Override 428 public <T extends Resource> T fetchResource( 429 Class<T> class_, String uri, String version, FhirPublication fhirVersion) { 430 throw new UnsupportedOperationException(Msg.code(2467)); 431 } 432 433 @Override 434 public <T extends Resource> T fetchResource(Class<T> class_, String uri, Resource canonicalForSource) { 435 return fetchResource(class_, uri); 436 } 437 438 @Override 439 public <T extends Resource> List<T> fetchResourcesByType(Class<T> class_, FhirPublication fhirVersion) { 440 throw new UnsupportedOperationException(Msg.code(2468)); 441 } 442 443 @Override 444 public org.hl7.fhir.r5.model.Resource fetchResourceById(String theType, String theUri) { 445 throw new UnsupportedOperationException(Msg.code(226)); 446 } 447 448 @Override 449 public Resource fetchResourceById(String type, String uri, FhirPublication fhirVersion) { 450 throw new UnsupportedOperationException(Msg.code(2469)); 451 } 452 453 @Override 454 public <T extends org.hl7.fhir.r5.model.Resource> boolean hasResource(Class<T> theClass_, String theUri) { 455 throw new UnsupportedOperationException(Msg.code(227)); 456 } 457 458 @Override 459 public <T extends Resource> boolean hasResource(Class<T> class_, String uri, Resource sourceOfReference) { 460 throw new UnsupportedOperationException(Msg.code(2470)); 461 } 462 463 @Override 464 public <T extends Resource> boolean hasResource(Class<T> class_, String uri, FhirPublication fhirVersion) { 465 throw new UnsupportedOperationException(Msg.code(2471)); 466 } 467 468 @Override 469 public void cacheResource(org.hl7.fhir.r5.model.Resource theRes) throws FHIRException { 470 throw new UnsupportedOperationException(Msg.code(228)); 471 } 472 473 @Override 474 public void cacheResourceFromPackage(Resource res, PackageInformation packageDetails) throws FHIRException { 475 throw new UnsupportedOperationException(Msg.code(229)); 476 } 477 478 @Override 479 public void cachePackage(PackageInformation packageInformation) {} 480 481 @Override 482 public Set<String> getResourceNamesAsSet() { 483 return myCtx.getResourceTypes(); 484 } 485 486 @Override 487 public Set<String> getResourceNamesAsSet(FhirPublication fhirVersion) { 488 throw new UnsupportedOperationException(Msg.code(2472)); 489 } 490 491 @Override 492 public ValueSetExpansionOutcome expandVS( 493 Resource src, ElementDefinitionBindingComponent theBinding, boolean theCacheOk, boolean theHierarchical) 494 throws FHIRException { 495 throw new UnsupportedOperationException(Msg.code(230)); 496 } 497 498 @Override 499 public Set<String> getBinaryKeysAsSet() { 500 throw new UnsupportedOperationException(Msg.code(2115)); 501 } 502 503 @Override 504 public boolean hasBinaryKey(String s) { 505 throw new UnsupportedOperationException(Msg.code(2129)); 506 } 507 508 @Override 509 public byte[] getBinaryForKey(String s) { 510 throw new UnsupportedOperationException(Msg.code(2199)); 511 } 512 513 @Override 514 public int loadFromPackage(NpmPackage pi, IContextResourceLoader loader) throws FHIRException { 515 throw new UnsupportedOperationException(Msg.code(233)); 516 } 517 518 @Override 519 public int loadFromPackage(NpmPackage pi, IContextResourceLoader loader, List<String> types) 520 throws FileNotFoundException, IOException, FHIRException { 521 throw new UnsupportedOperationException(Msg.code(2328)); 522 } 523 524 @Override 525 public int loadFromPackageAndDependencies(NpmPackage pi, IContextResourceLoader loader, BasePackageCacheManager pcm) 526 throws FHIRException { 527 throw new UnsupportedOperationException(Msg.code(235)); 528 } 529 530 @Override 531 public boolean hasPackage(String id, String ver) { 532 throw new UnsupportedOperationException(Msg.code(236)); 533 } 534 535 @Override 536 public boolean hasPackage(PackageInformation packageVersion) { 537 return false; 538 } 539 540 @Override 541 public PackageInformation getPackage(String id, String ver) { 542 return null; 543 } 544 545 @Override 546 public int getClientRetryCount() { 547 throw new UnsupportedOperationException(Msg.code(237)); 548 } 549 550 @Override 551 public IWorkerContext setClientRetryCount(int value) { 552 throw new UnsupportedOperationException(Msg.code(238)); 553 } 554 555 @Override 556 public TimeTracker clock() { 557 return null; 558 } 559 560 @Override 561 public IWorkerContextManager.IPackageLoadingTracker getPackageTracker() { 562 throw new UnsupportedOperationException(Msg.code(2112)); 563 } 564 565 @Override 566 public PackageInformation getPackageForUrl(String s) { 567 return null; 568 } 569 570 public static ConceptValidationOptions convertConceptValidationOptions(ValidationOptions theOptions) { 571 ConceptValidationOptions retVal = new ConceptValidationOptions(); 572 if (theOptions.isGuessSystem()) { 573 retVal = retVal.setInferSystem(true); 574 } 575 return retVal; 576 } 577 578 @Override 579 public <T extends Resource> List<T> fetchResourcesByType(Class<T> theClass) { 580 if (theClass.equals(StructureDefinition.class)) { 581 return myValidationSupport.fetchAllStructureDefinitions(); 582 } 583 584 throw new UnsupportedOperationException(Msg.code(2113) + "Can't fetch all resources of type: " + theClass); 585 } 586 587 @Override 588 public <T extends Resource> List<T> fetchResourcesByUrl(Class<T> class_, String url) { 589 throw new UnsupportedOperationException(Msg.code(2508) + "Can't fetch all resources of url: " + url); 590 } 591 592 @Override 593 public IWorkerContext setPackageTracker(IWorkerContextManager.IPackageLoadingTracker theIPackageLoadingTracker) { 594 throw new UnsupportedOperationException(Msg.code(220)); 595 } 596 597 @Override 598 public String getSpecUrl() { 599 return ""; 600 } 601 602 @Override 603 public PEBuilder getProfiledElementBuilder( 604 PEBuilder.PEElementPropertiesPolicy thePEElementPropertiesPolicy, boolean theB) { 605 throw new UnsupportedOperationException(Msg.code(2261)); 606 } 607 608 @Override 609 public boolean isForPublication() { 610 return false; 611 } 612 613 @Override 614 public void setForPublication(boolean b) { 615 throw new UnsupportedOperationException(Msg.code(2350)); 616 } 617 618 @Override 619 public OIDSummary urlsForOid(String oid, String resourceType) { 620 throw new UnsupportedOperationException(Msg.code(2473)); 621 } 622 623 @Override 624 public <T extends Resource> T findTxResource(Class<T> class_, String canonical, Resource sourceOfReference) { 625 throw new UnsupportedOperationException(Msg.code(2491)); 626 } 627 628 @Override 629 public <T extends Resource> T findTxResource(Class<T> class_, String canonical) { 630 throw new UnsupportedOperationException(Msg.code(2492)); 631 } 632 633 @Override 634 public <T extends Resource> T findTxResource(Class<T> class_, String canonical, String version) { 635 throw new UnsupportedOperationException(Msg.code(2493)); 636 } 637 638 @Override 639 public Boolean subsumes(ValidationOptions optionsArg, Coding parent, Coding child) { 640 throw new UnsupportedOperationException(Msg.code(2488)); 641 } 642 643 @Override 644 public boolean isServerSideSystem(String url) { 645 return false; 646 } 647}