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}