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