
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.getValidationResourceCacheTimeoutMillis(); 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 ValueSetExpansionOutcome expandVS(String s, boolean b, boolean b1, int i) { 215 return null; 216 } 217 218 @Override 219 public ValidationResult validateCode( 220 ValidationOptions theOptions, String theSystem, String theVersion, String theCode, String theDisplay) { 221 IValidationSupport.CodeValidationResult result = myValidationSupport.validateCode( 222 new ValidationSupportContext(myValidationSupport), 223 convertConceptValidationOptions(theOptions), 224 theSystem, 225 theCode, 226 theDisplay, 227 null); 228 if (result == null) { 229 return null; 230 } 231 IssueSeverity severity = null; 232 if (result.getSeverity() != null) { 233 severity = IssueSeverity.fromCode(result.getSeverityCode()); 234 } 235 ConceptDefinitionComponent definition = new ConceptDefinitionComponent().setCode(result.getCode()); 236 return new ValidationResult(severity, result.getMessage(), theSystem, theVersion, definition, null, null); 237 } 238 239 @Override 240 public ValidationResult validateCode( 241 ValidationOptions theOptions, 242 String theSystem, 243 String theVersion, 244 String theCode, 245 String theDisplay, 246 ValueSet theVs) { 247 IValidationSupport.CodeValidationResult outcome; 248 if (isNotBlank(theVs.getUrl())) { 249 outcome = myValidationSupport.validateCode( 250 new ValidationSupportContext(myValidationSupport), 251 convertConceptValidationOptions(theOptions), 252 theSystem, 253 theCode, 254 theDisplay, 255 theVs.getUrl()); 256 } else { 257 outcome = myValidationSupport.validateCodeInValueSet( 258 new ValidationSupportContext(myValidationSupport), 259 convertConceptValidationOptions(theOptions), 260 theSystem, 261 theCode, 262 theDisplay, 263 theVs); 264 } 265 266 if (outcome != null && outcome.isOk()) { 267 ConceptDefinitionComponent definition = new ConceptDefinitionComponent(); 268 definition.setCode(theCode); 269 definition.setDisplay(outcome.getDisplay()); 270 return new ValidationResult(theSystem, theVersion, definition, null); 271 } 272 273 return new ValidationResult( 274 IssueSeverity.ERROR, 275 "Unknown code[" + theCode + "] in system[" + Constants.codeSystemWithDefaultDescription(theSystem) 276 + "]", 277 null); 278 } 279 280 @Override 281 public ValidationResult validateCode(ValidationOptions theOptions, String code, ValueSet vs) { 282 return validateCode(theOptions, null, null, code, null, vs); 283 } 284 285 @Override 286 public Parameters getExpansionParameters() { 287 return myExpansionProfile; 288 } 289 290 @Override 291 public void setExpansionParameters(Parameters expParameters) { 292 setExpansionProfile(expParameters); 293 } 294 295 public void setExpansionProfile(Parameters theExpParameters) { 296 myExpansionProfile = theExpParameters; 297 } 298 299 @Override 300 public ValueSetExpansionOutcome expandVS(ValueSet theSource, boolean theCacheOk, boolean theHierarchical) { 301 throw new UnsupportedOperationException(Msg.code(2128)); 302 } 303 304 @Override 305 public ValueSetExpansionOutcome expandVS(ValueSet theSource, boolean theCacheOk, boolean theHierarchical, int i) { 306 throw new UnsupportedOperationException(Msg.code(2128)); 307 } 308 309 /*1@Override 310 public ValueSetExpansionOutcome expandVS(ConceptSetComponent theInc, boolean theHierarchical, boolean theNoInactive) 311 throws TerminologyServiceException { 312 ValueSet input = new ValueSet(); 313 input.getCompose().setInactive(!theNoInactive); // TODO GGG/DO is this valid? 314 input.getCompose().addInclude(theInc); 315 IValidationSupport.ValueSetExpansionOutcome output = 316 myValidationSupport.expandValueSet(new ValidationSupportContext(myValidationSupport), null, input); 317 return new ValueSetExpansionOutcome( 318 (ValueSet) output.getValueSet(), output.getError(), null, output.getErrorIsFromServer()); 319 }*/ 320 321 @Override 322 public Locale getLocale() { 323 return Locale.getDefault(); 324 } 325 326 @Override 327 public void setLocale(Locale locale) { 328 // ignore 329 } 330 331 @Override 332 public org.hl7.fhir.r5.context.ILoggingService getLogger() { 333 throw new UnsupportedOperationException(Msg.code(213)); 334 } 335 336 @Override 337 public void setLogger(org.hl7.fhir.r5.context.ILoggingService theLogger) { 338 throw new UnsupportedOperationException(Msg.code(214)); 339 } 340 341 @Override 342 public String getVersion() { 343 return myCtx.getVersion().getVersion().getFhirVersionString(); 344 } 345 346 @Override 347 public UcumService getUcumService() { 348 throw new UnsupportedOperationException(Msg.code(216)); 349 } 350 351 @Override 352 public void setUcumService(UcumService ucumService) { 353 throw new UnsupportedOperationException(Msg.code(217)); 354 } 355 356 @Override 357 public boolean isNoTerminologyServer() { 358 return false; 359 } 360 361 @Override 362 public Set<String> getCodeSystemsUsed() { 363 throw new UnsupportedOperationException(Msg.code(218)); 364 } 365 366 @Override 367 public StructureDefinition fetchTypeDefinition(String typeName) { 368 return fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + typeName); 369 } 370 371 @Override 372 public boolean isPrimitiveType(String s) { 373 throw new UnsupportedOperationException(Msg.code(2462)); 374 } 375 376 @Override 377 public boolean isDataType(String s) { 378 throw new UnsupportedOperationException(Msg.code(2463)); 379 } 380 381 @Override 382 public StructureDefinition fetchTypeDefinition(String typeName, FhirPublication fhirVersion) { 383 throw new UnsupportedOperationException(Msg.code(2464)); 384 } 385 386 @Override 387 public List<StructureDefinition> fetchTypeDefinitions(String n) { 388 throw new UnsupportedOperationException(Msg.code(234)); 389 } 390 391 @Override 392 public List<StructureDefinition> fetchTypeDefinitions(String n, FhirPublication fhirPublication) { 393 throw new UnsupportedOperationException(Msg.code(2465)); 394 } 395 396 @Override 397 public <T extends Resource> T fetchResourceRaw(Class<T> class_, String uri) { 398 return fetchResource(class_, uri); 399 } 400 401 @Override 402 public <T extends org.hl7.fhir.r5.model.Resource> T fetchResource(Class<T> theClass, String theUri) { 403 if (myValidationSupport == null || theUri == null) { 404 return null; 405 } else { 406 @SuppressWarnings("unchecked") 407 T retVal = (T) myFetchedResourceCache.get(theUri, t -> myValidationSupport.fetchResource(theClass, theUri)); 408 return retVal; 409 } 410 } 411 412 public <T extends Resource> T fetchResource(Class<T> class_, String uri, FhirPublication fhirVersion) { 413 throw new UnsupportedOperationException(Msg.code(2466)); 414 } 415 416 @Override 417 public <T extends org.hl7.fhir.r5.model.Resource> T fetchResourceWithException(Class<T> theClass, String theUri) 418 throws FHIRException { 419 T retVal = fetchResource(theClass, theUri); 420 if (retVal == null) { 421 throw new FHIRException(Msg.code(224) + "Could not find resource: " + theUri); 422 } 423 return retVal; 424 } 425 426 @Override 427 public <T extends Resource> T fetchResourceWithException(Class<T> theClass, String uri, Resource sourceOfReference) 428 throws FHIRException { 429 throw new UnsupportedOperationException(Msg.code(2213)); 430 } 431 432 @Override 433 public <T extends Resource> T fetchResource(Class<T> theClass, String theUri, String theVersion) { 434 return fetchResource(theClass, theUri + "|" + theVersion); 435 } 436 437 @Override 438 public <T extends Resource> T fetchResource( 439 Class<T> class_, String uri, String version, FhirPublication fhirVersion) { 440 throw new UnsupportedOperationException(Msg.code(2467)); 441 } 442 443 @Override 444 public <T extends Resource> T fetchResource(Class<T> class_, String uri, Resource canonicalForSource) { 445 return fetchResource(class_, uri); 446 } 447 448 @Override 449 public <T extends Resource> List<T> fetchResourcesByType(Class<T> class_, FhirPublication fhirVersion) { 450 throw new UnsupportedOperationException(Msg.code(2468)); 451 } 452 453 @Override 454 public org.hl7.fhir.r5.model.Resource fetchResourceById(String theType, String theUri) { 455 throw new UnsupportedOperationException(Msg.code(226)); 456 } 457 458 @Override 459 public Resource fetchResourceById(String type, String uri, FhirPublication fhirVersion) { 460 throw new UnsupportedOperationException(Msg.code(2469)); 461 } 462 463 @Override 464 public <T extends org.hl7.fhir.r5.model.Resource> boolean hasResource(Class<T> theClass_, String theUri) { 465 throw new UnsupportedOperationException(Msg.code(227)); 466 } 467 468 @Override 469 public <T extends Resource> boolean hasResource(Class<T> class_, String uri, Resource sourceOfReference) { 470 throw new UnsupportedOperationException(Msg.code(2470)); 471 } 472 473 @Override 474 public <T extends Resource> boolean hasResource(Class<T> class_, String uri, FhirPublication fhirVersion) { 475 throw new UnsupportedOperationException(Msg.code(2471)); 476 } 477 478 @Override 479 public void cacheResource(org.hl7.fhir.r5.model.Resource theRes) throws FHIRException { 480 throw new UnsupportedOperationException(Msg.code(228)); 481 } 482 483 @Override 484 public void cacheResourceFromPackage(Resource res, PackageInformation packageDetails) throws FHIRException { 485 throw new UnsupportedOperationException(Msg.code(229)); 486 } 487 488 @Override 489 public void cachePackage(PackageInformation packageInformation) {} 490 491 @Override 492 public Set<String> getResourceNamesAsSet() { 493 return myCtx.getResourceTypes(); 494 } 495 496 @Override 497 public Set<String> getResourceNamesAsSet(FhirPublication fhirVersion) { 498 throw new UnsupportedOperationException(Msg.code(2472)); 499 } 500 501 @Override 502 public ValueSetExpansionOutcome expandVS( 503 Resource src, ElementDefinitionBindingComponent theBinding, boolean theCacheOk, boolean theHierarchical) 504 throws FHIRException { 505 throw new UnsupportedOperationException(Msg.code(230)); 506 } 507 508 @Override 509 public ValueSetExpansionOutcome expandVS( 510 ITerminologyOperationDetails iTerminologyOperationDetails, 511 ConceptSetComponent conceptSetComponent, 512 boolean b, 513 boolean b1) 514 throws TerminologyServiceException { 515 return null; 516 } 517 518 @Override 519 public Set<String> getBinaryKeysAsSet() { 520 throw new UnsupportedOperationException(Msg.code(2115)); 521 } 522 523 @Override 524 public boolean hasBinaryKey(String s) { 525 throw new UnsupportedOperationException(Msg.code(2129)); 526 } 527 528 @Override 529 public byte[] getBinaryForKey(String s) { 530 throw new UnsupportedOperationException(Msg.code(2199)); 531 } 532 533 @Override 534 public int loadFromPackage(NpmPackage pi, IContextResourceLoader loader) throws FHIRException { 535 throw new UnsupportedOperationException(Msg.code(233)); 536 } 537 538 @Override 539 public int loadFromPackage(NpmPackage pi, IContextResourceLoader loader, List<String> types) 540 throws FileNotFoundException, IOException, FHIRException { 541 throw new UnsupportedOperationException(Msg.code(2328)); 542 } 543 544 @Override 545 public int loadFromPackageAndDependencies(NpmPackage pi, IContextResourceLoader loader, BasePackageCacheManager pcm) 546 throws FHIRException { 547 throw new UnsupportedOperationException(Msg.code(235)); 548 } 549 550 @Override 551 public boolean hasPackage(String id, String ver) { 552 throw new UnsupportedOperationException(Msg.code(236)); 553 } 554 555 @Override 556 public boolean hasPackage(PackageInformation packageVersion) { 557 return false; 558 } 559 560 @Override 561 public PackageInformation getPackage(String id, String ver) { 562 return null; 563 } 564 565 @Override 566 public int getClientRetryCount() { 567 throw new UnsupportedOperationException(Msg.code(237)); 568 } 569 570 @Override 571 public IWorkerContext setClientRetryCount(int value) { 572 throw new UnsupportedOperationException(Msg.code(238)); 573 } 574 575 @Override 576 public TimeTracker clock() { 577 return null; 578 } 579 580 @Override 581 public IWorkerContextManager.IPackageLoadingTracker getPackageTracker() { 582 throw new UnsupportedOperationException(Msg.code(2112)); 583 } 584 585 @Override 586 public PackageInformation getPackageForUrl(String s) { 587 return null; 588 } 589 590 public static ConceptValidationOptions convertConceptValidationOptions(ValidationOptions theOptions) { 591 ConceptValidationOptions retVal = new ConceptValidationOptions(); 592 if (theOptions.isGuessSystem()) { 593 retVal = retVal.setInferSystem(true); 594 } 595 return retVal; 596 } 597 598 @Override 599 public <T extends Resource> List<T> fetchResourcesByType(Class<T> theClass) { 600 if (theClass.equals(StructureDefinition.class)) { 601 return myValidationSupport.fetchAllStructureDefinitions(); 602 } 603 604 throw new UnsupportedOperationException(Msg.code(2113) + "Can't fetch all resources of type: " + theClass); 605 } 606 607 @Override 608 public <T extends Resource> List<T> fetchResourcesByUrl(Class<T> class_, String url) { 609 throw new UnsupportedOperationException(Msg.code(2508) + "Can't fetch all resources of url: " + url); 610 } 611 612 @Override 613 public IWorkerContext setPackageTracker(IWorkerContextManager.IPackageLoadingTracker theIPackageLoadingTracker) { 614 throw new UnsupportedOperationException(Msg.code(220)); 615 } 616 617 @Override 618 public String getSpecUrl() { 619 return ""; 620 } 621 622 @Override 623 public PEBuilder getProfiledElementBuilder( 624 PEBuilder.PEElementPropertiesPolicy thePEElementPropertiesPolicy, boolean theB) { 625 throw new UnsupportedOperationException(Msg.code(2261)); 626 } 627 628 @Override 629 public boolean isForPublication() { 630 return false; 631 } 632 633 @Override 634 public void setForPublication(boolean b) { 635 throw new UnsupportedOperationException(Msg.code(2350)); 636 } 637 638 @Override 639 public OIDSummary urlsForOid(String oid, String resourceType) { 640 throw new UnsupportedOperationException(Msg.code(2473)); 641 } 642 643 @Override 644 public <T extends Resource> T findTxResource(Class<T> class_, String canonical, Resource sourceOfReference) { 645 throw new UnsupportedOperationException(Msg.code(2491)); 646 } 647 648 @Override 649 public <T extends Resource> T findTxResource(Class<T> class_, String canonical) { 650 throw new UnsupportedOperationException(Msg.code(2492)); 651 } 652 653 @Override 654 public <T extends Resource> T findTxResource(Class<T> class_, String canonical, String version) { 655 throw new UnsupportedOperationException(Msg.code(2493)); 656 } 657 658 @Override 659 public Boolean subsumes(ValidationOptions optionsArg, Coding parent, Coding child) { 660 throw new UnsupportedOperationException(Msg.code(2488)); 661 } 662 663 @Override 664 public boolean isServerSideSystem(String url) { 665 return false; 666 } 667}