001package org.hl7.fhir.common.hapi.validation.validator; 002 003import ca.uhn.fhir.context.FhirContext; 004import ca.uhn.fhir.context.FhirVersionEnum; 005import ca.uhn.fhir.context.support.ConceptValidationOptions; 006import ca.uhn.fhir.context.support.IValidationSupport; 007import ca.uhn.fhir.context.support.ValidationSupportContext; 008import ca.uhn.fhir.i18n.Msg; 009import ca.uhn.fhir.rest.api.Constants; 010import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; 011import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException; 012import com.github.benmanes.caffeine.cache.Caffeine; 013import com.github.benmanes.caffeine.cache.LoadingCache; 014import org.apache.commons.lang3.Validate; 015import org.apache.commons.lang3.builder.EqualsBuilder; 016import org.apache.commons.lang3.builder.HashCodeBuilder; 017import org.apache.commons.lang3.time.DateUtils; 018import org.fhir.ucum.UcumService; 019import org.hl7.fhir.convertors.advisors.impl.BaseAdvisor_10_50; 020import org.hl7.fhir.convertors.factory.VersionConvertorFactory_10_50; 021import org.hl7.fhir.exceptions.FHIRException; 022import org.hl7.fhir.exceptions.TerminologyServiceException; 023import org.hl7.fhir.instance.model.api.IBaseResource; 024import org.hl7.fhir.r5.context.IWorkerContext; 025import org.hl7.fhir.r5.formats.IParser; 026import org.hl7.fhir.r5.formats.ParserType; 027import org.hl7.fhir.r5.model.CanonicalResource; 028import org.hl7.fhir.r5.model.CodeSystem; 029import org.hl7.fhir.r5.model.Coding; 030import org.hl7.fhir.r5.model.NamingSystem; 031import org.hl7.fhir.r5.model.Resource; 032import org.hl7.fhir.r5.model.StructureDefinition; 033import org.hl7.fhir.r5.model.ValueSet; 034import org.hl7.fhir.r5.terminologies.ValueSetExpander; 035import org.hl7.fhir.r5.utils.validation.IResourceValidator; 036import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier; 037import org.hl7.fhir.utilities.TimeTracker; 038import org.hl7.fhir.utilities.TranslationServices; 039import org.hl7.fhir.utilities.i18n.I18nBase; 040import org.hl7.fhir.utilities.npm.BasePackageCacheManager; 041import org.hl7.fhir.utilities.npm.NpmPackage; 042import org.hl7.fhir.utilities.validation.ValidationMessage; 043import org.hl7.fhir.utilities.validation.ValidationOptions; 044import org.slf4j.Logger; 045import org.slf4j.LoggerFactory; 046 047import javax.annotation.Nonnull; 048import javax.annotation.Nullable; 049import java.util.ArrayList; 050import java.util.List; 051import java.util.Locale; 052import java.util.Map; 053import java.util.Set; 054import java.util.concurrent.TimeUnit; 055 056import static org.apache.commons.lang3.StringUtils.isBlank; 057import static org.apache.commons.lang3.StringUtils.isNotBlank; 058 059public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWorkerContext { 060 public static final IVersionTypeConverter IDENTITY_VERSION_TYPE_CONVERTER = new VersionTypeConverterR5(); 061 private static final Logger ourLog = LoggerFactory.getLogger(VersionSpecificWorkerContextWrapper.class); 062 private static final FhirContext ourR5Context = FhirContext.forR5(); 063 private final ValidationSupportContext myValidationSupportContext; 064 private final IVersionTypeConverter myModelConverter; 065 private final LoadingCache<ResourceKey, IBaseResource> myFetchResourceCache; 066 private volatile List<StructureDefinition> myAllStructures; 067 private org.hl7.fhir.r5.model.Parameters myExpansionProfile; 068 069 public VersionSpecificWorkerContextWrapper(ValidationSupportContext theValidationSupportContext, IVersionTypeConverter theModelConverter) { 070 myValidationSupportContext = theValidationSupportContext; 071 myModelConverter = theModelConverter; 072 073 long timeoutMillis = 10 * DateUtils.MILLIS_PER_SECOND; 074 if (System.getProperties().containsKey(ca.uhn.fhir.rest.api.Constants.TEST_SYSTEM_PROP_VALIDATION_RESOURCE_CACHES_MS)) { 075 timeoutMillis = Long.parseLong(System.getProperty(Constants.TEST_SYSTEM_PROP_VALIDATION_RESOURCE_CACHES_MS)); 076 } 077 078 myFetchResourceCache = Caffeine.newBuilder() 079 .expireAfterWrite(timeoutMillis, TimeUnit.MILLISECONDS) 080 .maximumSize(10000) 081 .build(key -> { 082 083 String fetchResourceName = key.getResourceName(); 084 if (myValidationSupportContext.getRootValidationSupport().getFhirContext().getVersion().getVersion() == FhirVersionEnum.DSTU2) { 085 if ("CodeSystem".equals(fetchResourceName)) { 086 fetchResourceName = "ValueSet"; 087 } 088 } 089 090 Class<? extends IBaseResource> fetchResourceType; 091 if (fetchResourceName.equals("Resource")) { 092 fetchResourceType = null; 093 } else { 094 fetchResourceType = myValidationSupportContext.getRootValidationSupport().getFhirContext().getResourceDefinition(fetchResourceName).getImplementingClass(); 095 } 096 097 IBaseResource fetched = myValidationSupportContext.getRootValidationSupport().fetchResource(fetchResourceType, key.getUri()); 098 099 Resource canonical = myModelConverter.toCanonical(fetched); 100 101 if (canonical instanceof StructureDefinition) { 102 StructureDefinition canonicalSd = (StructureDefinition) canonical; 103 if (canonicalSd.getSnapshot().isEmpty()) { 104 ourLog.info("Generating snapshot for StructureDefinition: {}", canonicalSd.getUrl()); 105 fetched = myValidationSupportContext.getRootValidationSupport().generateSnapshot(theValidationSupportContext, fetched, "", null, ""); 106 Validate.isTrue(fetched != null, "StructureDefinition %s has no snapshot, and no snapshot generator is configured", key.getUri()); 107 canonical = myModelConverter.toCanonical(fetched); 108 } 109 } 110 111 return canonical; 112 }); 113 114 setValidationMessageLanguage(getLocale()); 115 } 116 117 @Override 118 public List<CanonicalResource> allConformanceResources() { 119 throw new UnsupportedOperationException(Msg.code(650)); 120 } 121 122 @Override 123 public String getLinkForUrl(String corePath, String url) { 124 throw new UnsupportedOperationException(Msg.code(651)); 125 } 126 127 @Override 128 public Set<String> getBinaryKeysAsSet() { 129 throw new UnsupportedOperationException(Msg.code(2118)); 130 } 131 132 @Override 133 public boolean hasBinaryKey(String s) { 134 return myValidationSupportContext.getRootValidationSupport().fetchBinary(s) != null; 135 } 136 137 @Override 138 public byte[] getBinaryForKey(String s) { 139 return myValidationSupportContext.getRootValidationSupport().fetchBinary(s); 140 } 141 142 @Override 143 public int loadFromPackage(NpmPackage pi, IContextResourceLoader loader) throws FHIRException { 144 throw new UnsupportedOperationException(Msg.code(652)); 145 } 146 147 @Override 148 public int loadFromPackage(NpmPackage pi, IContextResourceLoader loader, String[] types) throws FHIRException { 149 throw new UnsupportedOperationException(Msg.code(653)); 150 } 151 152 @Override 153 public int loadFromPackageAndDependencies(NpmPackage pi, IContextResourceLoader loader, BasePackageCacheManager pcm) throws FHIRException { 154 throw new UnsupportedOperationException(Msg.code(654)); 155 } 156 157 @Override 158 public boolean hasPackage(String id, String ver) { 159 throw new UnsupportedOperationException(Msg.code(655)); 160 } 161 162 @Override 163 public boolean hasPackage(PackageVersion packageVersion) { 164 return false; 165 } 166 167 @Override 168 public PackageDetails getPackage(PackageVersion packageVersion) { 169 return null; 170 } 171 172 @Override 173 public int getClientRetryCount() { 174 throw new UnsupportedOperationException(Msg.code(656)); 175 } 176 177 @Override 178 public IWorkerContext setClientRetryCount(int value) { 179 throw new UnsupportedOperationException(Msg.code(657)); 180 } 181 182 @Override 183 public TimeTracker clock() { 184 return null; 185 } 186 187 @Override 188 public IPackageLoadingTracker getPackageTracker() { 189 throw new UnsupportedOperationException(Msg.code(2108)); 190 } 191 192 @Override 193 public IWorkerContext setPackageTracker( 194 IPackageLoadingTracker packageTracker) { 195 throw new UnsupportedOperationException(Msg.code(2114)); 196 } 197 198 @Override 199 public PackageVersion getPackageForUrl(String s) { 200 throw new UnsupportedOperationException(Msg.code(2109)); 201 } 202 203 @Override 204 public void generateSnapshot(StructureDefinition input) throws FHIRException { 205 if (input.hasSnapshot()) { 206 return; 207 } 208 209 org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider profileKnowledgeProvider = new ProfileKnowledgeWorkerR5(ourR5Context); 210 ArrayList<ValidationMessage> messages = new ArrayList<>(); 211 org.hl7.fhir.r5.model.StructureDefinition base = fetchResource(StructureDefinition.class, input.getBaseDefinition()); 212 if (base == null) { 213 throw new PreconditionFailedException(Msg.code(658) + "Unknown base definition: " + input.getBaseDefinition()); 214 } 215 new org.hl7.fhir.r5.conformance.ProfileUtilities(this, messages, profileKnowledgeProvider).generateSnapshot(base, input, "", null, ""); 216 217 } 218 219 @Override 220 public void generateSnapshot(StructureDefinition theStructureDefinition, boolean theB) { 221 // nothing yet 222 } 223 224 @Override 225 public org.hl7.fhir.r5.model.Parameters getExpansionParameters() { 226 return myExpansionProfile; 227 } 228 229 @Override 230 public void setExpansionProfile(org.hl7.fhir.r5.model.Parameters expParameters) { 231 myExpansionProfile = expParameters; 232 } 233 234 @Override 235 public List<StructureDefinition> allStructures() { 236 237 List<StructureDefinition> retVal = myAllStructures; 238 if (retVal == null) { 239 retVal = new ArrayList<>(); 240 for (IBaseResource next : myValidationSupportContext.getRootValidationSupport().fetchAllStructureDefinitions()) { 241 try { 242 Resource converted = myModelConverter.toCanonical(next); 243 retVal.add((StructureDefinition) converted); 244 } catch (FHIRException e) { 245 throw new InternalErrorException(Msg.code(659) + e); 246 } 247 } 248 myAllStructures = retVal; 249 } 250 251 return retVal; 252 } 253 254 @Override 255 public List<StructureDefinition> getStructures() { 256 return allStructures(); 257 } 258 259 @Override 260 public void cacheResource(Resource res) { 261 262 } 263 264 @Override 265 public void cacheResourceFromPackage(Resource res, PackageVersion packageDetails) throws FHIRException { 266 267 } 268 269 @Override 270 public void cachePackage(PackageDetails packageDetails, List<PackageVersion> list) { 271 272 } 273 274 @Nonnull 275 private ValidationResult convertValidationResult(String theSystem, @Nullable IValidationSupport.CodeValidationResult theResult) { 276 ValidationResult retVal = null; 277 if (theResult != null) { 278 String code = theResult.getCode(); 279 String display = theResult.getDisplay(); 280 String issueSeverity = theResult.getSeverityCode(); 281 String message = theResult.getMessage(); 282 if (isNotBlank(code)) { 283 retVal = new ValidationResult(theSystem, new org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent() 284 .setCode(code) 285 .setDisplay(display)); 286 } else if (isNotBlank(issueSeverity)) { 287 retVal = new ValidationResult(ValidationMessage.IssueSeverity.fromCode(issueSeverity), message, ValueSetExpander.TerminologyServiceErrorClass.UNKNOWN); 288 } 289 290 } 291 292 if (retVal == null) { 293 retVal = new ValidationResult(ValidationMessage.IssueSeverity.ERROR, "Validation failed"); 294 } 295 296 return retVal; 297 } 298 299 @Override 300 public ValueSetExpander.ValueSetExpansionOutcome expandVS(org.hl7.fhir.r5.model.ValueSet source, boolean cacheOk, boolean Hierarchical) { 301 IBaseResource convertedSource; 302 try { 303 convertedSource = myModelConverter.fromCanonical(source); 304 } catch (FHIRException e) { 305 throw new InternalErrorException(Msg.code(661) + e); 306 } 307 IValidationSupport.ValueSetExpansionOutcome expanded = myValidationSupportContext.getRootValidationSupport().expandValueSet(myValidationSupportContext, null, convertedSource); 308 309 org.hl7.fhir.r5.model.ValueSet convertedResult = null; 310 if (expanded.getValueSet() != null) { 311 try { 312 convertedResult = (ValueSet) myModelConverter.toCanonical(expanded.getValueSet()); 313 } catch (FHIRException e) { 314 throw new InternalErrorException(Msg.code(662) + e); 315 } 316 } 317 318 String error = expanded.getError(); 319 ValueSetExpander.TerminologyServiceErrorClass result = null; 320 321 return new ValueSetExpander.ValueSetExpansionOutcome(convertedResult, error, result); 322 } 323 324 @Override 325 public ValueSetExpander.ValueSetExpansionOutcome expandVS(org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent binding, boolean cacheOk, boolean Hierarchical) { 326 throw new UnsupportedOperationException(Msg.code(663)); 327 } 328 329 @Override 330 public ValueSetExpander.ValueSetExpansionOutcome expandVS(ValueSet.ConceptSetComponent inc, boolean hierarchical, boolean noInactive) throws TerminologyServiceException { 331 throw new UnsupportedOperationException(Msg.code(664)); 332 } 333 334 @Override 335 public Locale getLocale() { 336 return myValidationSupportContext.getRootValidationSupport().getFhirContext().getLocalizer().getLocale(); 337 } 338 339 @Override 340 public void setLocale(Locale locale) { 341 // ignore 342 } 343 344 @Override 345 public org.hl7.fhir.r5.model.CodeSystem fetchCodeSystem(String system) { 346 IBaseResource fetched = myValidationSupportContext.getRootValidationSupport().fetchCodeSystem(system); 347 if (fetched == null) { 348 return null; 349 } 350 try { 351 return (org.hl7.fhir.r5.model.CodeSystem) myModelConverter.toCanonical(fetched); 352 } catch (FHIRException e) { 353 throw new InternalErrorException(Msg.code(665) + e); 354 } 355 } 356 357 @Override 358 public CodeSystem fetchCodeSystem(String system, String verison) { 359 IBaseResource fetched = myValidationSupportContext.getRootValidationSupport().fetchCodeSystem(system); 360 if (fetched == null) { 361 return null; 362 } 363 try { 364 return (org.hl7.fhir.r5.model.CodeSystem) myModelConverter.toCanonical(fetched); 365 } catch (FHIRException e) { 366 throw new InternalErrorException(Msg.code(1992) + e); 367 } 368 } 369 370 @Override 371 public <T extends Resource> T fetchResource(Class<T> class_, String uri) { 372 373 if (isBlank(uri)) { 374 return null; 375 } 376 377 ResourceKey key = new ResourceKey(class_.getSimpleName(), uri); 378 @SuppressWarnings("unchecked") 379 T retVal = (T) myFetchResourceCache.get(key); 380 381 return retVal; 382 } 383 384 @Override 385 public Resource fetchResourceById(String type, String uri) { 386 throw new UnsupportedOperationException(Msg.code(666)); 387 } 388 389 @Override 390 public <T extends Resource> T fetchResourceWithException(Class<T> class_, String uri) throws FHIRException { 391 T retVal = fetchResource(class_, uri); 392 if (retVal == null) { 393 throw new FHIRException(Msg.code(667) + "Can not find resource of type " + class_.getSimpleName() + " with uri " + uri); 394 } 395 return retVal; 396 } 397 398 @Override 399 public <T extends Resource> T fetchResource(Class<T> class_, String uri, String version) { 400 return fetchResource(class_, uri + "|" + version); 401 } 402 403 @Override 404 public <T extends Resource> T fetchResource(Class<T> class_, String uri, CanonicalResource canonicalForSource) { 405 throw new UnsupportedOperationException(Msg.code(668)); 406 } 407 408 @Override 409 public List<org.hl7.fhir.r5.model.ConceptMap> findMapsForSource(String url) { 410 throw new UnsupportedOperationException(Msg.code(669)); 411 } 412 413 @Override 414 public String getAbbreviation(String name) { 415 throw new UnsupportedOperationException(Msg.code(670)); 416 } 417 418 @Override 419 public IParser getParser(ParserType type) { 420 throw new UnsupportedOperationException(Msg.code(671)); 421 } 422 423 @Override 424 public IParser getParser(String type) { 425 throw new UnsupportedOperationException(Msg.code(672)); 426 } 427 428 @Override 429 public List<String> getResourceNames() { 430 return new ArrayList<>(myValidationSupportContext.getRootValidationSupport().getFhirContext().getResourceTypes()); 431 } 432 433 @Override 434 public Set<String> getResourceNamesAsSet() { 435 return myValidationSupportContext.getRootValidationSupport().getFhirContext().getResourceTypes(); 436 } 437 438 @Override 439 public List<String> getCanonicalResourceNames() { 440 throw new UnsupportedOperationException(Msg.code(2110)); 441 } 442 443 @Override 444 public org.hl7.fhir.r5.model.StructureMap getTransform(String url) { 445 throw new UnsupportedOperationException(Msg.code(673)); 446 } 447 448 @Override 449 public String getOverrideVersionNs() { 450 return null; 451 } 452 453 @Override 454 public void setOverrideVersionNs(String value) { 455 throw new UnsupportedOperationException(Msg.code(674)); 456 } 457 458 @Override 459 public StructureDefinition fetchTypeDefinition(String typeName) { 460 return fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + typeName); 461 } 462 463 @Override 464 public StructureDefinition fetchRawProfile(String url) { 465 StructureDefinition retVal = fetchResource(StructureDefinition.class, url); 466 467 if (retVal != null && retVal.getSnapshot().isEmpty()) { 468 generateSnapshot(retVal); 469 } 470 471 return retVal; 472 } 473 474 @Override 475 public List<String> getTypeNames() { 476 throw new UnsupportedOperationException(Msg.code(675)); 477 } 478 479 @Override 480 public UcumService getUcumService() { 481 throw new UnsupportedOperationException(Msg.code(676)); 482 } 483 484 @Override 485 public void setUcumService(UcumService ucumService) { 486 throw new UnsupportedOperationException(Msg.code(677)); 487 } 488 489 @Override 490 public String getVersion() { 491 return myValidationSupportContext.getRootValidationSupport().getFhirContext().getVersion().getVersion().getFhirVersionString(); 492 } 493 494 @Override 495 public String getSpecUrl() { 496 throw new UnsupportedOperationException(Msg.code(678)); 497 } 498 499 @Override 500 public boolean hasCache() { 501 throw new UnsupportedOperationException(Msg.code(679)); 502 } 503 504 @Override 505 public <T extends Resource> boolean hasResource(Class<T> class_, String uri) { 506 throw new UnsupportedOperationException(Msg.code(680)); 507 } 508 509 @Override 510 public boolean isNoTerminologyServer() { 511 return false; 512 } 513 514 @Override 515 public Set<String> getCodeSystemsUsed() { 516 throw new UnsupportedOperationException(Msg.code(681)); 517 } 518 519 @Override 520 public List<org.hl7.fhir.r5.model.StructureMap> listTransforms() { 521 throw new UnsupportedOperationException(Msg.code(682)); 522 } 523 524 @Override 525 public IParser newJsonParser() { 526 throw new UnsupportedOperationException(Msg.code(683)); 527 } 528 529 @Override 530 public IResourceValidator newValidator() { 531 throw new UnsupportedOperationException(Msg.code(684)); 532 } 533 534 @Override 535 public IParser newXmlParser() { 536 throw new UnsupportedOperationException(Msg.code(685)); 537 } 538 539 @Override 540 public String oid2Uri(String code) { 541 throw new UnsupportedOperationException(Msg.code(686)); 542 } 543 544 @Override 545 public Map<String, NamingSystem> getNSUrlMap() { 546 throw new UnsupportedOperationException(Msg.code(2111)); 547 } 548 549 @Override 550 public ILoggingService getLogger() { 551 return null; 552 } 553 554 @Override 555 public void setLogger(ILoggingService logger) { 556 throw new UnsupportedOperationException(Msg.code(687)); 557 } 558 559 @Override 560 public boolean supportsSystem(String system) { 561 return myValidationSupportContext.getRootValidationSupport().isCodeSystemSupported(myValidationSupportContext, system); 562 } 563 564 @Override 565 public TranslationServices translator() { 566 throw new UnsupportedOperationException(Msg.code(688)); 567 } 568 569 @Override 570 public ValueSetExpander.ValueSetExpansionOutcome expandVS(ValueSet source, boolean cacheOk, boolean heiarchical, boolean incompleteOk) { 571 return null; 572 } 573 574 @Override 575 public ValidationResult validateCode(ValidationOptions theOptions, String system, String version, String code, String display) { 576 ConceptValidationOptions validationOptions = convertConceptValidationOptions(theOptions); 577 return doValidation(null, validationOptions, system, code, display); 578 } 579 580 @Override 581 public ValidationResult validateCode(ValidationOptions theOptions, String theSystem, String version, String theCode, String display, ValueSet theValueSet) { 582 IBaseResource convertedVs = null; 583 584 try { 585 if (theValueSet != null) { 586 convertedVs = myModelConverter.fromCanonical(theValueSet); 587 } 588 } catch (FHIRException e) { 589 throw new InternalErrorException(Msg.code(689) + e); 590 } 591 592 ConceptValidationOptions validationOptions = convertConceptValidationOptions(theOptions); 593 594 return doValidation(convertedVs, validationOptions, theSystem, theCode, display); 595 } 596 597 @Override 598 public ValidationResult validateCode(ValidationOptions theOptions, String code, org.hl7.fhir.r5.model.ValueSet theValueSet) { 599 IBaseResource convertedVs = null; 600 try { 601 if (theValueSet != null) { 602 convertedVs = myModelConverter.fromCanonical(theValueSet); 603 } 604 } catch (FHIRException e) { 605 throw new InternalErrorException(Msg.code(690) + e); 606 } 607 608 ConceptValidationOptions validationOptions = convertConceptValidationOptions(theOptions).setInferSystem(true); 609 610 return doValidation(convertedVs, validationOptions, null, code, null); 611 } 612 613 @Override 614 public ValidationResult validateCode(ValidationOptions theOptions, org.hl7.fhir.r5.model.Coding theCoding, org.hl7.fhir.r5.model.ValueSet theValueSet) { 615 IBaseResource convertedVs = null; 616 617 try { 618 if (theValueSet != null) { 619 convertedVs = myModelConverter.fromCanonical(theValueSet); 620 } 621 } catch (FHIRException e) { 622 throw new InternalErrorException(Msg.code(691) + e); 623 } 624 625 ConceptValidationOptions validationOptions = convertConceptValidationOptions(theOptions); 626 String system = theCoding.getSystem(); 627 String code = theCoding.getCode(); 628 String display = theCoding.getDisplay(); 629 630 return doValidation(convertedVs, validationOptions, system, code, display); 631 } 632 633 @Override 634 public ValidationResult validateCode(ValidationOptions options, Coding code, ValueSet vs, ValidationContextCarrier ctxt) { 635 return validateCode(options, code, vs); 636 } 637 638 @Override 639 public void validateCodeBatch(ValidationOptions options, List<? extends CodingValidationRequest> codes, ValueSet vs) { 640 for (CodingValidationRequest next : codes) { 641 ValidationResult outcome = validateCode(options, next.getCoding(), vs); 642 next.setResult(outcome); 643 } 644 } 645 646 @Nonnull 647 private ValidationResult doValidation(IBaseResource theValueSet, ConceptValidationOptions theValidationOptions, String theSystem, String theCode, String theDisplay) { 648 IValidationSupport.CodeValidationResult result; 649 if (theValueSet != null) { 650 result = myValidationSupportContext.getRootValidationSupport().validateCodeInValueSet(myValidationSupportContext, theValidationOptions, theSystem, theCode, theDisplay, theValueSet); 651 } else { 652 result = myValidationSupportContext.getRootValidationSupport().validateCode(myValidationSupportContext, theValidationOptions, theSystem, theCode, theDisplay, null); 653 } 654 return convertValidationResult(theSystem, result); 655 } 656 657 @Override 658 public ValidationResult validateCode(ValidationOptions theOptions, org.hl7.fhir.r5.model.CodeableConcept code, org.hl7.fhir.r5.model.ValueSet theVs) { 659 for (Coding next : code.getCoding()) { 660 ValidationResult retVal = validateCode(theOptions, next, theVs); 661 if (retVal.isOk()) { 662 return retVal; 663 } 664 } 665 666 return new ValidationResult(ValidationMessage.IssueSeverity.ERROR, null); 667 } 668 669 public void invalidateCaches() { 670 myFetchResourceCache.invalidateAll(); 671 } 672 673 public interface IVersionTypeConverter { 674 675 org.hl7.fhir.r5.model.Resource toCanonical(IBaseResource theNonCanonical); 676 677 IBaseResource fromCanonical(org.hl7.fhir.r5.model.Resource theCanonical); 678 679 } 680 681 private static class ResourceKey { 682 private final int myHashCode; 683 private final String myResourceName; 684 private final String myUri; 685 686 private ResourceKey(String theResourceName, String theUri) { 687 myResourceName = theResourceName; 688 myUri = theUri; 689 myHashCode = new HashCodeBuilder(17, 37) 690 .append(myResourceName) 691 .append(myUri) 692 .toHashCode(); 693 } 694 695 @Override 696 public boolean equals(Object theO) { 697 if (this == theO) { 698 return true; 699 } 700 701 if (theO == null || getClass() != theO.getClass()) { 702 return false; 703 } 704 705 ResourceKey that = (ResourceKey) theO; 706 707 return new EqualsBuilder() 708 .append(myResourceName, that.myResourceName) 709 .append(myUri, that.myUri) 710 .isEquals(); 711 } 712 713 public String getResourceName() { 714 return myResourceName; 715 } 716 717 public String getUri() { 718 return myUri; 719 } 720 721 @Override 722 public int hashCode() { 723 return myHashCode; 724 } 725 } 726 727 private static class VersionTypeConverterR5 implements IVersionTypeConverter { 728 @Override 729 public Resource toCanonical(IBaseResource theNonCanonical) { 730 return (Resource) theNonCanonical; 731 } 732 733 @Override 734 public IBaseResource fromCanonical(Resource theCanonical) { 735 return theCanonical; 736 } 737 } 738 739 public static ConceptValidationOptions convertConceptValidationOptions(ValidationOptions theOptions) { 740 ConceptValidationOptions retVal = new ConceptValidationOptions(); 741 if (theOptions.isGuessSystem()) { 742 retVal = retVal.setInferSystem(true); 743 } 744 return retVal; 745 } 746 747 @Nonnull 748 public static VersionSpecificWorkerContextWrapper newVersionSpecificWorkerContextWrapper(IValidationSupport theValidationSupport) { 749 IVersionTypeConverter converter; 750 751 switch (theValidationSupport.getFhirContext().getVersion().getVersion()) { 752 case DSTU2: 753 case DSTU2_HL7ORG: { 754 converter = new IVersionTypeConverter() { 755 @Override 756 public Resource toCanonical(IBaseResource theNonCanonical) { 757 Resource retVal = VersionConvertorFactory_10_50.convertResource((org.hl7.fhir.dstu2.model.Resource) theNonCanonical, new BaseAdvisor_10_50(false)); 758 if (theNonCanonical instanceof org.hl7.fhir.dstu2.model.ValueSet) { 759 org.hl7.fhir.dstu2.model.ValueSet valueSet = (org.hl7.fhir.dstu2.model.ValueSet) theNonCanonical; 760 if (valueSet.hasCodeSystem() && valueSet.getCodeSystem().hasSystem()) { 761 if (!valueSet.hasCompose()) { 762 ValueSet valueSetR5 = (ValueSet) retVal; 763 valueSetR5.getCompose().addInclude().setSystem(valueSet.getCodeSystem().getSystem()); 764 } 765 } 766 } 767 return retVal; 768 } 769 770 @Override 771 public IBaseResource fromCanonical(Resource theCanonical) { 772 return VersionConvertorFactory_10_50.convertResource(theCanonical, new BaseAdvisor_10_50(false)); 773 } 774 }; 775 break; 776 } 777 778 case DSTU2_1: { 779 converter = new VersionTypeConverterDstu21(); 780 break; 781 } 782 783 case DSTU3: { 784 converter = new VersionTypeConverterDstu3(); 785 break; 786 } 787 788 case R4: { 789 converter = new VersionTypeConverterR4(); 790 break; 791 } 792 793 case R4B: { 794 converter = new VersionTypeConverterR4B(); 795 break; 796 } 797 798 case R5: { 799 converter = IDENTITY_VERSION_TYPE_CONVERTER; 800 break; 801 } 802 803 default: 804 throw new IllegalStateException(Msg.code(692)); 805 } 806 807 return new VersionSpecificWorkerContextWrapper(new ValidationSupportContext(theValidationSupport), converter); 808 } 809} 810 811 812