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