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 SystemSupportInformation getTxSupportInfo(String system, String version) {
170                return null;
171        }
172
173        @Override
174        public SystemSupportInformation getTxSupportInfo(String system) {
175                return null;
176        }
177
178        @Override
179        public ValidationResult validateCode(ValidationOptions theOptions, CodeableConcept theCode, ValueSet theVs) {
180                for (Coding next : theCode.getCoding()) {
181                        ValidationResult retVal = validateCode(theOptions, next, theVs);
182                        if (retVal.isOk()) {
183                                return retVal;
184                        }
185                }
186
187                return new ValidationResult(IssueSeverity.ERROR, null, null);
188        }
189
190        @Override
191        public ValidationResult validateCode(ValidationOptions theOptions, Coding theCode, ValueSet theVs) {
192                String system = theCode.getSystem();
193                String code = theCode.getCode();
194                String display = theCode.getDisplay();
195                return validateCode(theOptions, system, null, code, display, theVs);
196        }
197
198        @Override
199        public ValidationResult validateCode(
200                        ValidationOptions options, Coding code, ValueSet vs, ValidationContextCarrier ctxt) {
201                return validateCode(options, code, vs);
202        }
203
204        @Override
205        public void validateCodeBatch(
206                        ValidationOptions options, List<? extends CodingValidationRequest> codes, ValueSet vs, boolean passVS) {}
207
208        @Override
209        public ValueSetExpansionOutcome expandVS(
210                        ValueSet theValueSet, boolean cacheOk, boolean heiarchical, boolean incompleteOk) {
211                return null;
212        }
213
214        @Override
215        public ValueSetExpansionOutcome expandVS(String s, boolean b, boolean b1, int i) {
216                return null;
217        }
218
219        @Override
220        public ValidationResult validateCode(
221                        ValidationOptions theOptions, String theSystem, String theVersion, String theCode, String theDisplay) {
222                IValidationSupport.CodeValidationResult result = myValidationSupport.validateCode(
223                                new ValidationSupportContext(myValidationSupport),
224                                convertConceptValidationOptions(theOptions),
225                                theSystem,
226                                theCode,
227                                theDisplay,
228                                null);
229                if (result == null) {
230                        return null;
231                }
232                IssueSeverity severity = null;
233                if (result.getSeverity() != null) {
234                        severity = IssueSeverity.fromCode(result.getSeverityCode());
235                }
236                ConceptDefinitionComponent definition = new ConceptDefinitionComponent().setCode(result.getCode());
237                return new ValidationResult(severity, result.getMessage(), theSystem, theVersion, definition, null, null);
238        }
239
240        @Override
241        public ValidationResult validateCode(
242                        ValidationOptions theOptions,
243                        String theSystem,
244                        String theVersion,
245                        String theCode,
246                        String theDisplay,
247                        ValueSet theVs) {
248                IValidationSupport.CodeValidationResult outcome;
249                if (isNotBlank(theVs.getUrl())) {
250                        outcome = myValidationSupport.validateCode(
251                                        new ValidationSupportContext(myValidationSupport),
252                                        convertConceptValidationOptions(theOptions),
253                                        theSystem,
254                                        theCode,
255                                        theDisplay,
256                                        theVs.getUrl());
257                } else {
258                        outcome = myValidationSupport.validateCodeInValueSet(
259                                        new ValidationSupportContext(myValidationSupport),
260                                        convertConceptValidationOptions(theOptions),
261                                        theSystem,
262                                        theCode,
263                                        theDisplay,
264                                        theVs);
265                }
266
267                if (outcome != null && outcome.isOk()) {
268                        ConceptDefinitionComponent definition = new ConceptDefinitionComponent();
269                        definition.setCode(theCode);
270                        definition.setDisplay(outcome.getDisplay());
271                        return new ValidationResult(theSystem, theVersion, definition, null);
272                }
273
274                return new ValidationResult(
275                                IssueSeverity.ERROR,
276                                "Unknown code[" + theCode + "] in system[" + Constants.codeSystemWithDefaultDescription(theSystem)
277                                                + "]",
278                                null);
279        }
280
281        @Override
282        public ValidationResult validateCode(ValidationOptions theOptions, String code, ValueSet vs) {
283                return validateCode(theOptions, null, null, code, null, vs);
284        }
285
286        @Override
287        public Parameters getExpansionParameters() {
288                return myExpansionProfile;
289        }
290
291        @Override
292        public void setExpansionParameters(Parameters expParameters) {
293                setExpansionProfile(expParameters);
294        }
295
296        public void setExpansionProfile(Parameters theExpParameters) {
297                myExpansionProfile = theExpParameters;
298        }
299
300        @Override
301        public ValueSetExpansionOutcome expandVS(ValueSet theSource, boolean theCacheOk, boolean theHierarchical) {
302                throw new UnsupportedOperationException(Msg.code(2128));
303        }
304
305        @Override
306        public ValueSetExpansionOutcome expandVS(ValueSet theSource, boolean theCacheOk, boolean theHierarchical, int i) {
307                throw new UnsupportedOperationException(Msg.code(2650));
308        }
309
310        /*1@Override
311        public ValueSetExpansionOutcome expandVS(ConceptSetComponent theInc, boolean theHierarchical, boolean theNoInactive)
312                        throws TerminologyServiceException {
313                ValueSet input = new ValueSet();
314                input.getCompose().setInactive(!theNoInactive); // TODO GGG/DO is this valid?
315                input.getCompose().addInclude(theInc);
316                IValidationSupport.ValueSetExpansionOutcome output =
317                                myValidationSupport.expandValueSet(new ValidationSupportContext(myValidationSupport), null, input);
318                return new ValueSetExpansionOutcome(
319                                (ValueSet) output.getValueSet(), output.getError(), null, output.getErrorIsFromServer());
320        }*/
321
322        @Override
323        public Locale getLocale() {
324                return Locale.getDefault();
325        }
326
327        @Override
328        public void setLocale(Locale locale) {
329                // ignore
330        }
331
332        @Override
333        public org.hl7.fhir.r5.context.ILoggingService getLogger() {
334                throw new UnsupportedOperationException(Msg.code(213));
335        }
336
337        @Override
338        public void setLogger(org.hl7.fhir.r5.context.ILoggingService theLogger) {
339                throw new UnsupportedOperationException(Msg.code(214));
340        }
341
342        @Override
343        public String getVersion() {
344                return myCtx.getVersion().getVersion().getFhirVersionString();
345        }
346
347        @Override
348        public UcumService getUcumService() {
349                throw new UnsupportedOperationException(Msg.code(216));
350        }
351
352        @Override
353        public void setUcumService(UcumService ucumService) {
354                throw new UnsupportedOperationException(Msg.code(217));
355        }
356
357        @Override
358        public boolean isNoTerminologyServer() {
359                return false;
360        }
361
362        @Override
363        public Set<String> getCodeSystemsUsed() {
364                throw new UnsupportedOperationException(Msg.code(218));
365        }
366
367        @Override
368        public StructureDefinition fetchTypeDefinition(String typeName) {
369                return fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + typeName);
370        }
371
372        @Override
373        public boolean isPrimitiveType(String s) {
374                throw new UnsupportedOperationException(Msg.code(2462));
375        }
376
377        @Override
378        public boolean isDataType(String s) {
379                throw new UnsupportedOperationException(Msg.code(2463));
380        }
381
382        @Override
383        public StructureDefinition fetchTypeDefinition(String typeName, FhirPublication fhirVersion) {
384                throw new UnsupportedOperationException(Msg.code(2464));
385        }
386
387        @Override
388        public List<StructureDefinition> fetchTypeDefinitions(String n) {
389                throw new UnsupportedOperationException(Msg.code(234));
390        }
391
392        @Override
393        public List<StructureDefinition> fetchTypeDefinitions(String n, FhirPublication fhirPublication) {
394                throw new UnsupportedOperationException(Msg.code(2465));
395        }
396
397        @Override
398        public <T extends Resource> T fetchResourceRaw(Class<T> class_, String uri) {
399                return fetchResource(class_, uri);
400        }
401
402        @Override
403        public <T extends org.hl7.fhir.r5.model.Resource> T fetchResource(Class<T> theClass, String theUri) {
404                if (myValidationSupport == null || theUri == null) {
405                        return null;
406                } else {
407                        @SuppressWarnings("unchecked")
408                        T retVal = (T) myFetchedResourceCache.get(theUri, t -> myValidationSupport.fetchResource(theClass, theUri));
409                        return retVal;
410                }
411        }
412
413        public <T extends Resource> T fetchResource(Class<T> class_, String uri, FhirPublication fhirVersion) {
414                throw new UnsupportedOperationException(Msg.code(2466));
415        }
416
417        @Override
418        public <T extends org.hl7.fhir.r5.model.Resource> T fetchResourceWithException(Class<T> theClass, String theUri)
419                        throws FHIRException {
420                T retVal = fetchResource(theClass, theUri);
421                if (retVal == null) {
422                        throw new FHIRException(Msg.code(224) + "Could not find resource: " + theUri);
423                }
424                return retVal;
425        }
426
427        @Override
428        public <T extends Resource> T fetchResourceWithException(Class<T> theClass, String uri, Resource sourceOfReference)
429                        throws FHIRException {
430                throw new UnsupportedOperationException(Msg.code(2213));
431        }
432
433        @Override
434        public <T extends Resource> T fetchResource(Class<T> theClass, String theUri, String theVersion) {
435                return fetchResource(theClass, theUri + "|" + theVersion);
436        }
437
438        @Override
439        public <T extends Resource> T fetchResource(
440                        Class<T> class_, String uri, String version, FhirPublication fhirVersion) {
441                throw new UnsupportedOperationException(Msg.code(2467));
442        }
443
444        @Override
445        public <T extends Resource> T fetchResource(Class<T> class_, String uri, Resource canonicalForSource) {
446                return fetchResource(class_, uri);
447        }
448
449        @Override
450        public <T extends Resource> List<T> fetchResourcesByType(Class<T> class_, FhirPublication fhirVersion) {
451                throw new UnsupportedOperationException(Msg.code(2468));
452        }
453
454        @Override
455        public org.hl7.fhir.r5.model.Resource fetchResourceById(String theType, String theUri) {
456                throw new UnsupportedOperationException(Msg.code(226));
457        }
458
459        @Override
460        public Resource fetchResourceById(String type, String uri, FhirPublication fhirVersion) {
461                throw new UnsupportedOperationException(Msg.code(2469));
462        }
463
464        @Override
465        public <T extends org.hl7.fhir.r5.model.Resource> boolean hasResource(Class<T> theClass_, String theUri) {
466                throw new UnsupportedOperationException(Msg.code(227));
467        }
468
469        @Override
470        public <T extends Resource> boolean hasResource(Class<T> class_, String uri, Resource sourceOfReference) {
471                throw new UnsupportedOperationException(Msg.code(2470));
472        }
473
474        @Override
475        public <T extends Resource> boolean hasResource(Class<T> class_, String uri, FhirPublication fhirVersion) {
476                throw new UnsupportedOperationException(Msg.code(2471));
477        }
478
479        @Override
480        public void cacheResource(org.hl7.fhir.r5.model.Resource theRes) throws FHIRException {
481                throw new UnsupportedOperationException(Msg.code(228));
482        }
483
484        @Override
485        public void cacheResourceFromPackage(Resource res, PackageInformation packageDetails) throws FHIRException {
486                throw new UnsupportedOperationException(Msg.code(229));
487        }
488
489        @Override
490        public void cachePackage(PackageInformation packageInformation) {}
491
492        @Override
493        public Set<String> getResourceNamesAsSet() {
494                return myCtx.getResourceTypes();
495        }
496
497        @Override
498        public Set<String> getResourceNamesAsSet(FhirPublication fhirVersion) {
499                throw new UnsupportedOperationException(Msg.code(2472));
500        }
501
502        @Override
503        public ValueSetExpansionOutcome expandVS(
504                        Resource src, ElementDefinitionBindingComponent theBinding, boolean theCacheOk, boolean theHierarchical)
505                        throws FHIRException {
506                throw new UnsupportedOperationException(Msg.code(230));
507        }
508
509        @Override
510        public ValueSetExpansionOutcome expandVS(
511                        ITerminologyOperationDetails iTerminologyOperationDetails,
512                        ConceptSetComponent conceptSetComponent,
513                        boolean b,
514                        boolean b1)
515                        throws TerminologyServiceException {
516                return null;
517        }
518
519        @Override
520        public Set<String> getBinaryKeysAsSet() {
521                throw new UnsupportedOperationException(Msg.code(2115));
522        }
523
524        @Override
525        public boolean hasBinaryKey(String s) {
526                throw new UnsupportedOperationException(Msg.code(2129));
527        }
528
529        @Override
530        public byte[] getBinaryForKey(String s) {
531                throw new UnsupportedOperationException(Msg.code(2199));
532        }
533
534        @Override
535        public int loadFromPackage(NpmPackage pi, IContextResourceLoader loader) throws FHIRException {
536                throw new UnsupportedOperationException(Msg.code(233));
537        }
538
539        @Override
540        public int loadFromPackageAndDependencies(NpmPackage pi, IContextResourceLoader loader, BasePackageCacheManager pcm)
541                        throws FHIRException {
542                throw new UnsupportedOperationException(Msg.code(235));
543        }
544
545        @Override
546        public boolean hasPackage(String id, String ver) {
547                throw new UnsupportedOperationException(Msg.code(236));
548        }
549
550        @Override
551        public boolean hasPackage(PackageInformation packageVersion) {
552                return false;
553        }
554
555        @Override
556        public PackageInformation getPackage(String id, String ver) {
557                return null;
558        }
559
560        @Override
561        public int getClientRetryCount() {
562                throw new UnsupportedOperationException(Msg.code(237));
563        }
564
565        @Override
566        public IWorkerContext setClientRetryCount(int value) {
567                throw new UnsupportedOperationException(Msg.code(238));
568        }
569
570        @Override
571        public TimeTracker clock() {
572                return null;
573        }
574
575        @Override
576        public IWorkerContextManager.IPackageLoadingTracker getPackageTracker() {
577                throw new UnsupportedOperationException(Msg.code(2112));
578        }
579
580        @Override
581        public PackageInformation getPackageForUrl(String s) {
582                return null;
583        }
584
585        public static ConceptValidationOptions convertConceptValidationOptions(ValidationOptions theOptions) {
586                ConceptValidationOptions retVal = new ConceptValidationOptions();
587                if (theOptions.isGuessSystem()) {
588                        retVal = retVal.setInferSystem(true);
589                }
590                return retVal;
591        }
592
593        @Override
594        public <T extends Resource> List<T> fetchResourcesByType(Class<T> theClass) {
595                if (theClass.equals(StructureDefinition.class)) {
596                        return myValidationSupport.fetchAllStructureDefinitions();
597                }
598
599                throw new UnsupportedOperationException(Msg.code(2113) + "Can't fetch all resources of type: " + theClass);
600        }
601
602        @Override
603        public <T extends Resource> List<T> fetchResourceVersionsByTypeAndUrl(Class<T> class_, String url) {
604                throw new UnsupportedOperationException(
605                                Msg.code(2796) + "Can't fetch all resources of type : " + class_ + " and url: " + url);
606        }
607
608        @Override
609        public <T extends Resource> List<T> fetchResourcesByUrl(Class<T> class_, String url) {
610                throw new UnsupportedOperationException(Msg.code(2508) + "Can't fetch all resources of url: " + url);
611        }
612
613        @Override
614        public IWorkerContext setPackageTracker(IWorkerContextManager.IPackageLoadingTracker theIPackageLoadingTracker) {
615                throw new UnsupportedOperationException(Msg.code(220));
616        }
617
618        @Override
619        public String getSpecUrl() {
620                return "";
621        }
622
623        @Override
624        public PEBuilder getProfiledElementBuilder(
625                        PEBuilder.PEElementPropertiesPolicy thePEElementPropertiesPolicy, boolean theB) {
626                throw new UnsupportedOperationException(Msg.code(2261));
627        }
628
629        @Override
630        public boolean isForPublication() {
631                return false;
632        }
633
634        @Override
635        public void setForPublication(boolean b) {
636                throw new UnsupportedOperationException(Msg.code(2350));
637        }
638
639        @Override
640        public OIDSummary urlsForOid(String oid, String resourceType) {
641                throw new UnsupportedOperationException(Msg.code(2473));
642        }
643
644        @Override
645        public <T extends Resource> T findTxResource(Class<T> class_, String canonical, Resource sourceOfReference) {
646                throw new UnsupportedOperationException(Msg.code(2491));
647        }
648
649        @Override
650        public <T extends Resource> T findTxResource(Class<T> class_, String canonical) {
651                throw new UnsupportedOperationException(Msg.code(2492));
652        }
653
654        @Override
655        public <T extends Resource> T findTxResource(Class<T> class_, String canonical, String version) {
656                throw new UnsupportedOperationException(Msg.code(2493));
657        }
658
659        @Override
660        public Boolean subsumes(ValidationOptions optionsArg, Coding parent, Coding child) {
661                throw new UnsupportedOperationException(Msg.code(2488));
662        }
663
664        @Override
665        public boolean isServerSideSystem(String url) {
666                return false;
667        }
668
669        @Override
670        public OperationOutcome validateTxResource(ValidationOptions options, Resource resource) {
671                throw new UnsupportedOperationException(Msg.code(2734));
672        }
673}