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