001package org.hl7.fhir.r4.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 ca.uhn.fhir.util.CoverageIgnore; 013import org.apache.commons.lang3.Validate; 014import org.fhir.ucum.UcumService; 015import org.hl7.fhir.exceptions.FHIRException; 016import org.hl7.fhir.exceptions.TerminologyServiceException; 017import org.hl7.fhir.r4.context.IWorkerContext; 018import org.hl7.fhir.r4.formats.IParser; 019import org.hl7.fhir.r4.formats.ParserType; 020import org.hl7.fhir.r4.model.CodeSystem; 021import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent; 022import org.hl7.fhir.r4.model.CodeableConcept; 023import org.hl7.fhir.r4.model.Coding; 024import org.hl7.fhir.r4.model.ConceptMap; 025import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionBindingComponent; 026import org.hl7.fhir.r4.model.MetadataResource; 027import org.hl7.fhir.r4.model.Parameters; 028import org.hl7.fhir.r4.model.Resource; 029import org.hl7.fhir.r4.model.ResourceType; 030import org.hl7.fhir.r4.model.StructureDefinition; 031import org.hl7.fhir.r4.model.StructureMap; 032import org.hl7.fhir.r4.model.ValueSet; 033import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent; 034import org.hl7.fhir.r4.terminologies.ValueSetExpander; 035import org.hl7.fhir.r4.utils.validation.IResourceValidator; 036import org.hl7.fhir.utilities.TranslationServices; 037import org.hl7.fhir.utilities.i18n.I18nBase; 038import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; 039import org.hl7.fhir.utilities.validation.ValidationOptions; 040 041import java.util.ArrayList; 042import java.util.Arrays; 043import java.util.Collections; 044import java.util.HashSet; 045import java.util.List; 046import java.util.Set; 047 048import static org.apache.commons.lang3.StringUtils.isNotBlank; 049 050public final class HapiWorkerContext extends I18nBase implements IWorkerContext { 051 private final FhirContext myCtx; 052 private final Cache<String, Resource> myFetchedResourceCache; 053 private IValidationSupport myValidationSupport; 054 private Parameters myExpansionProfile; 055 private String myOverrideVersionNs; 056 057 public HapiWorkerContext(FhirContext theCtx, IValidationSupport theValidationSupport) { 058 Validate.notNull(theCtx, "theCtx must not be null"); 059 Validate.notNull(theValidationSupport, "theValidationSupport must not be null"); 060 myCtx = theCtx; 061 myValidationSupport = theValidationSupport; 062 063 long timeoutMillis = HapiSystemProperties.getTestValidationResourceCachesMs(); 064 065 myFetchedResourceCache = CacheFactory.build(timeoutMillis); 066 067 // Set a default locale 068 setValidationMessageLanguage(getLocale()); 069 } 070 071 @Override 072 public List<StructureDefinition> allStructures() { 073 return myValidationSupport.fetchAllStructureDefinitions(); 074 } 075 076 @Override 077 public List<StructureDefinition> getStructures() { 078 return allStructures(); 079 } 080 081 @Override 082 public CodeSystem fetchCodeSystem(String theSystem) { 083 if (myValidationSupport == null) { 084 return null; 085 } else { 086 return (CodeSystem) myValidationSupport.fetchCodeSystem(theSystem); 087 } 088 } 089 090 @Override 091 public List<ConceptMap> findMapsForSource(String theUrl) { 092 throw new UnsupportedOperationException(Msg.code(258)); 093 } 094 095 @Override 096 public String getAbbreviation(String theName) { 097 throw new UnsupportedOperationException(Msg.code(259)); 098 } 099 100 @Override 101 public org.hl7.fhir.r4.utils.INarrativeGenerator getNarrativeGenerator(String thePrefix, String theBasePath) { 102 throw new UnsupportedOperationException(Msg.code(260)); 103 } 104 105 @Override 106 public IParser getParser(ParserType theType) { 107 throw new UnsupportedOperationException(Msg.code(261)); 108 } 109 110 @Override 111 public IParser getParser(String theType) { 112 throw new UnsupportedOperationException(Msg.code(262)); 113 } 114 115 @Override 116 public List<String> getResourceNames() { 117 List<String> result = new ArrayList<>(); 118 for (ResourceType next : ResourceType.values()) { 119 result.add(next.name()); 120 } 121 Collections.sort(result); 122 return result; 123 } 124 125 @Override 126 public IParser newJsonParser() { 127 throw new UnsupportedOperationException(Msg.code(263)); 128 } 129 130 @Override 131 public IResourceValidator newValidator() { 132 throw new UnsupportedOperationException(Msg.code(264)); 133 } 134 135 @Override 136 public IParser newXmlParser() { 137 throw new UnsupportedOperationException(Msg.code(265)); 138 } 139 140 @Override 141 public String oid2Uri(String theCode) { 142 throw new UnsupportedOperationException(Msg.code(266)); 143 } 144 145 @Override 146 public boolean supportsSystem(String theSystem) { 147 if (myValidationSupport == null) { 148 return false; 149 } else { 150 return myValidationSupport.isCodeSystemSupported(new ValidationSupportContext(myValidationSupport), theSystem); 151 } 152 } 153 154 @Override 155 public Set<String> typeTails() { 156 return new HashSet<>(Arrays.asList("Integer", "UnsignedInt", "PositiveInt", "Decimal", "DateTime", "Date", "Time", "Instant", "String", "Uri", "Oid", "Uuid", "Id", "Boolean", "Code", 157 "Markdown", "Base64Binary", "Coding", "CodeableConcept", "Attachment", "Identifier", "Quantity", "SampledData", "Range", "Period", "Ratio", "HumanName", "Address", "ContactPoint", 158 "Timing", "Reference", "Annotation", "Signature", "Meta")); 159 } 160 161 @Override 162 public ValidationResult validateCode(ValidationOptions theOptions, CodeableConcept theCode, ValueSet theVs) { 163 for (Coding next : theCode.getCoding()) { 164 ValidationResult retVal = validateCode(theOptions, next, theVs); 165 if (retVal.isOk()) { 166 return retVal; 167 } 168 } 169 170 return new ValidationResult(IssueSeverity.ERROR, null); 171 } 172 173 @Override 174 public ValidationResult validateCode(ValidationOptions theOptions, Coding theCode, ValueSet theVs) { 175 String system = theCode.getSystem(); 176 String code = theCode.getCode(); 177 String display = theCode.getDisplay(); 178 return validateCode(theOptions, system, code, display, theVs); 179 } 180 181 @Override 182 public ValidationResult validateCode(ValidationOptions theOptions, String theSystem, String theCode, String theDisplay) { 183 IValidationSupport.CodeValidationResult result = myValidationSupport.validateCode(new ValidationSupportContext(myValidationSupport), convertConceptValidationOptions(theOptions), theSystem, theCode, theDisplay, null); 184 if (result == null) { 185 return null; 186 } 187 188 IssueSeverity severity = null; 189 if (result.getSeverity() != null) { 190 severity = IssueSeverity.fromCode(result.getSeverityCode()); 191 } 192 193 ConceptDefinitionComponent definition = new ConceptDefinitionComponent().setCode(result.getCode()); 194 return new ValidationResult(severity, result.getMessage(), definition); 195 } 196 197 @Override 198 public ValidationResult validateCode(ValidationOptions theOptions, String theSystem, String theCode, String theDisplay, ConceptSetComponent theVsi) { 199 throw new UnsupportedOperationException(Msg.code(267)); 200 } 201 202 203 @Override 204 public ValidationResult validateCode(ValidationOptions theOptions, String theSystem, String theCode, String theDisplay, ValueSet theVs) { 205 206 IValidationSupport.CodeValidationResult outcome; 207 if (isNotBlank(theVs.getUrl())) { 208 outcome = myValidationSupport.validateCode(new ValidationSupportContext(myValidationSupport), convertConceptValidationOptions(theOptions), theSystem, theCode, theDisplay, theVs.getUrl()); 209 } else { 210 outcome = myValidationSupport.validateCodeInValueSet(new ValidationSupportContext(myValidationSupport), convertConceptValidationOptions(theOptions), theSystem, theCode, theDisplay, theVs); 211 } 212 213 if (outcome != null && outcome.isOk()) { 214 ConceptDefinitionComponent definition = new ConceptDefinitionComponent(); 215 definition.setCode(theCode); 216 definition.setDisplay(outcome.getDisplay()); 217 return new ValidationResult(definition); 218 } 219 220 return new ValidationResult(IssueSeverity.ERROR, "Unknown code[" + theCode + "] in system[" + Constants.codeSystemWithDefaultDescription(theSystem) + "]"); 221 } 222 223 @Override 224 public ValidationResult validateCode(ValidationOptions theOptions, String code, ValueSet vs) { 225 ValidationOptions options = theOptions.guessSystem(); 226 return validateCode(options, null, code, null, vs); 227 } 228 229 @Override 230 @CoverageIgnore 231 public List<MetadataResource> allConformanceResources() { 232 throw new UnsupportedOperationException(Msg.code(268)); 233 } 234 235 @Override 236 public void generateSnapshot(StructureDefinition p) throws FHIRException { 237 throw new UnsupportedOperationException(Msg.code(269)); 238 } 239 240 @Override 241 public Parameters getExpansionParameters() { 242 return myExpansionProfile; 243 } 244 245 @Override 246 public void setExpansionProfile(Parameters theExpParameters) { 247 myExpansionProfile = theExpParameters; 248 } 249 250 @Override 251 @CoverageIgnore 252 public boolean hasCache() { 253 throw new UnsupportedOperationException(Msg.code(270)); 254 } 255 256 @Override 257 public ValueSetExpander.ValueSetExpansionOutcome expandVS(ValueSet theSource, boolean theCacheOk, boolean theHierarchical) { 258 throw new UnsupportedOperationException(Msg.code(271)); 259 } 260 261 @Override 262 public ValueSetExpander.ValueSetExpansionOutcome expandVS(ConceptSetComponent theInc, boolean theHierarchical) throws TerminologyServiceException { 263 ValueSet input = new ValueSet(); 264 input.getCompose().addInclude(theInc); 265 IValidationSupport.ValueSetExpansionOutcome output = myValidationSupport.expandValueSet(new ValidationSupportContext(myValidationSupport), null, input); 266 return new ValueSetExpander.ValueSetExpansionOutcome((ValueSet) output.getValueSet(), output.getError(), null); 267 } 268 269 @Override 270 public ILoggingService getLogger() { 271 throw new UnsupportedOperationException(Msg.code(272)); 272 } 273 274 @Override 275 public void setLogger(ILoggingService theLogger) { 276 throw new UnsupportedOperationException(Msg.code(273)); 277 } 278 279 @Override 280 public String getVersion() { 281 return myCtx.getVersion().getVersion().getFhirVersionString(); 282 } 283 284 @Override 285 public UcumService getUcumService() { 286 throw new UnsupportedOperationException(Msg.code(274)); 287 } 288 289 @Override 290 public void setUcumService(UcumService ucumService) { 291 throw new UnsupportedOperationException(Msg.code(275)); 292 } 293 294 @Override 295 public boolean isNoTerminologyServer() { 296 return false; 297 } 298 299 @Override 300 public TranslationServices translator() { 301 throw new UnsupportedOperationException(Msg.code(276)); 302 } 303 304 @Override 305 public List<StructureMap> listTransforms() { 306 throw new UnsupportedOperationException(Msg.code(277)); 307 } 308 309 @Override 310 public StructureMap getTransform(String url) { 311 throw new UnsupportedOperationException(Msg.code(278)); 312 } 313 314 @Override 315 public String getOverrideVersionNs() { 316 return myOverrideVersionNs; 317 } 318 319 @Override 320 public void setOverrideVersionNs(String value) { 321 myOverrideVersionNs = value; 322 } 323 324 @Override 325 public StructureDefinition fetchTypeDefinition(String theTypeName) { 326 return fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + theTypeName); 327 } 328 329 @Override 330 public String getLinkForUrl(String corePath, String url) { 331 throw new UnsupportedOperationException(Msg.code(279)); 332 } 333 334 @Override 335 public List<String> getTypeNames() { 336 throw new UnsupportedOperationException(Msg.code(280)); 337 } 338 339 @Override 340 public <T extends org.hl7.fhir.r4.model.Resource> T fetchResource(Class<T> theClass, String theUri) { 341 if (myValidationSupport == null || theUri == null) { 342 return null; 343 } else { 344 @SuppressWarnings("unchecked") 345 T retVal = (T) myFetchedResourceCache.get(theUri, t -> myValidationSupport.fetchResource(theClass, theUri)); 346 return retVal; 347 } 348 } 349 350 @Override 351 public <T extends org.hl7.fhir.r4.model.Resource> T fetchResourceWithException(Class<T> theClass, String theUri) throws FHIRException { 352 T retVal = fetchResource(theClass, theUri); 353 if (retVal == null) { 354 throw new FHIRException(Msg.code(281) + "Could not find resource: " + theUri); 355 } 356 return retVal; 357 } 358 359 @Override 360 public org.hl7.fhir.r4.model.Resource fetchResourceById(String theType, String theUri) { 361 throw new UnsupportedOperationException(Msg.code(282)); 362 } 363 364 @Override 365 public <T extends org.hl7.fhir.r4.model.Resource> boolean hasResource(Class<T> theClass_, String theUri) { 366 throw new UnsupportedOperationException(Msg.code(283)); 367 } 368 369 @Override 370 public void cacheResource(org.hl7.fhir.r4.model.Resource theRes) throws FHIRException { 371 throw new UnsupportedOperationException(Msg.code(284)); 372 } 373 374 @Override 375 public Set<String> getResourceNamesAsSet() { 376 return myCtx.getResourceTypes(); 377 } 378 379 @Override 380 public ValueSetExpander.ValueSetExpansionOutcome expandVS(ElementDefinitionBindingComponent theBinding, boolean theCacheOk, boolean theHierarchical) throws FHIRException { 381 throw new UnsupportedOperationException(Msg.code(285)); 382 } 383 384 public static ConceptValidationOptions convertConceptValidationOptions(ValidationOptions theOptions) { 385 ConceptValidationOptions retVal = new ConceptValidationOptions(); 386 if (theOptions.isGuessSystem()) { 387 retVal = retVal.setInferSystem(true); 388 } 389 return retVal; 390 } 391 392}